From f182e6749cfdc0fd36a4d9bfcc711ba9f14195e8 Mon Sep 17 00:00:00 2001
From: Rtch90 <ritchie.cunningham@protonmail.com>
Date: Sun, 2 Sep 2012 23:57:19 +0100
Subject: [PATCH] [Add] I don't want to talk about it.

-- Should be pretty usable now.
---
 Bin/LibD.pro                                 |   4 +
 src/System/Filesystem/EmptyBuffer.h          |   2 +-
 src/System/Filesystem/FileInputStream.cpp    | 119 ++++++++++++++++++
 src/System/Filesystem/FilePackageManager.cpp | 106 ++++++++++++++++
 src/System/Filesystem/FilePackageManager.h   |  32 +++++
 src/System/Filesystem/IFilePackage.h         |   2 +-
 src/System/Filesystem/InputFileStream.cpp    | 122 +++++++++++++++++++
 src/System/Filesystem/InputFileStream.h      |  30 +++++
 8 files changed, 415 insertions(+), 2 deletions(-)
 create mode 100644 src/System/Filesystem/FileInputStream.cpp
 create mode 100644 src/System/Filesystem/FilePackageManager.cpp
 create mode 100644 src/System/Filesystem/FilePackageManager.h
 create mode 100644 src/System/Filesystem/InputFileStream.cpp
 create mode 100644 src/System/Filesystem/InputFileStream.h

diff --git a/Bin/LibD.pro b/Bin/LibD.pro
index 72cb8d3..a16cd08 100644
--- a/Bin/LibD.pro
+++ b/Bin/LibD.pro
@@ -43,6 +43,8 @@ HEADERS += ../src/Actor/Player.h \
     ../src/System/Filesystem/IFileList.h \
     ../src/System/Filesystem/IFilePackage.h \
     ../src/System/Filesystem/FileList.h \
+    ../src/System/Filesystem/InputFileStream.h \
+    ../src/System/Filesystem/FilePackageManager.h \
     ../src/Texture/Texture.h \
     ../src/Sound/Music.h \
     ../src/TMXParser/base64.h \
@@ -95,6 +97,8 @@ SOURCES += ../src/Actor/Player.cpp \
     ../src/System/Debug.cpp \
     ../src/System/Filesystem/InputStream.cpp \
     ../src/System/Filesystem/FileList.cpp \
+    ../src/System/Filesystem/InputFileStream.cpp \
+    ../src/System/Filesystem/FilePackageManager.cpp \
     ../src/Texture/Texture.cpp \
     ../src/Sound/Music.cpp \
     ../src/Actor/NPC.cpp \
diff --git a/src/System/Filesystem/EmptyBuffer.h b/src/System/Filesystem/EmptyBuffer.h
index 802dca5..498e657 100644
--- a/src/System/Filesystem/EmptyBuffer.h
+++ b/src/System/Filesystem/EmptyBuffer.h
@@ -5,7 +5,7 @@
 namespace saracraft {
 namespace filesystem {
 
-struct EmptyBuffer: public IINputStreamBuffer {
+struct EmptyBuffer: public IInputStreamBuffer {
   unsigned char PopByte(void) { return 0; }
   bool IsEof(void) const      { return true; }
   int GetSize(void) const     { return 0; }
diff --git a/src/System/Filesystem/FileInputStream.cpp b/src/System/Filesystem/FileInputStream.cpp
new file mode 100644
index 0000000..45d9619
--- /dev/null
+++ b/src/System/Filesystem/FileInputStream.cpp
@@ -0,0 +1,119 @@
+#include <fstream>
+#include "../Debug.h"
+#include "InputFileStream.h"
+
+namespace saracraft {
+namespace filesystem {
+
+struct InputFileStreamBufferData {
+  FILE* fp;
+  size_t size;
+
+  InputFileStreamBufferData(const std::string filename) : fp(0), size(0) {
+    fp = fopen(filename.c_str(), "rb");
+
+#ifdef __UNIX__
+    // Another ugly as hell case sensitive hack.
+    // if anyone finds a nice way to handle this. Please implement it. -- Allanis
+    if(!fp) {
+      std::string filename = filename;
+      for(unsigned int i = 0; i < filename.size(); i++) {
+        if(isupper(filename[i]))
+          filename[i] = tolower(filename[i]);
+        else if(filename[i] == '\\')
+          filename[i] = '/';
+      }
+      fp = fopen(filename.c_str(), "rb");
+    }
+#endif
+    if(fp) {
+      fseek(fp, 0, SEEK_END);
+      size = ftell(fp);
+      fseek(fp, 0, SEEK_SET);
+    }
+    if(!size)
+      Close();
+  }
+
+  ~InputFileStreamBufferData(void) {
+    Close();
+  }
+
+  void Close(void) {
+    if(fp) {
+      fclose(fp);
+      fp = 0;
+    }
+  }
+};
+
+InputFileStreamBuffer::~InputFileStreamBuffer(void) {
+
+}
+
+unsigned char InputFileStreamBuffer::PopByte(void) {
+  char byte = 0;
+  if(_data->fp) {
+    int input = fgetc(_data->fp);
+    if(input == EOF)
+      _data->Close();
+    else
+      byte = (char)input;
+  }
+  return byte;
+}
+
+bool InputFileStreamBuffer::IsEof(void) const {
+  if(!_data->fp)
+    return true;
+
+  return false;
+}
+
+int InputFileStreamBuffer::GetSize(void) const {
+  if(!_data->fp)
+    return 0;
+
+  // This could cause maybe about a 2GB limimitation to file size
+  // by casting to int. Feel free to FIXME.
+  // -- Allanis
+  return int(_data->size);
+}
+
+void InputFileStreamBuffer::PopBytes(char* buffer, int bytes) {
+  if(!_data->fp) {
+    for(int i = 0; i < bytes; ++i)
+      buffer[i] = 0;
+  } else {
+    //_data->stream.read(buffer, bytes);
+    if(fread(buffer, 1, bytes, _data->fp) != (unsigned)bytes)
+      _data->Close();
+  }
+}
+
+// HACK: ffs. This is needed to get some sense into the input stream error reporting.
+//bool input_file_stream_no_nonexisting_error_message = false;
+
+//void SetInputStreamErrorReporting(bool logNonExisting) {
+//  input_file_stream_no_nonexisting_error_message = !logNonExisting;
+//}
+
+InputStream CreateInputFileStream(const std::string& filename) {
+
+  InputStream inputStream;
+  boost::shared_ptr<InputFileStreamBuffer> inputBuffer(new InputBuffer(filename));
+  // Eh.. No.
+  // TODO: Would need a seperate error check, eof is not the same as the file does not exist..
+  // This would just spam error messages. We don't want that.
+  /*if(!inputBuffer->IsEof()) {
+    if(!input_file_stream_no_nonexisting_error_message) {
+      Debug->logger("CreateInputFileStream - File \"%s\"does not exist or is zero length.", filename.c_str());
+    }
+  }*/
+  inputStream.SetBuffer(inputBuffer);
+  return inputStream;
+}
+
+} // Namespace filesystem.
+} // Namespace saracraft.
+
diff --git a/src/System/Filesystem/FilePackageManager.cpp b/src/System/Filesystem/FilePackageManager.cpp
new file mode 100644
index 0000000..f7226e8
--- /dev/null
+++ b/src/System/Filesystem/FilePackageManager.cpp
@@ -0,0 +1,106 @@
+#include <map>
+#include "../Debug.h"
+#include "FilePackageManager.h"
+#include "EmptyBuffer.h"
+#include "FileList.h"
+
+// HACK: This is not a good dependancy for error reporting.
+// We are going to use it anyway though.
+#include "InputFileStream.h"
+
+namespace saracraft {
+namespace filesystem {
+namespace {
+typedef std::multimap<int, boost::shared_ptr<IFilePackage> > PackageMap;
+  FilePackageManager instance;
+  FilePackageManager* instancePtr = 0;
+} // Unamed namespace.
+
+struct FilePackageManagerData {
+  PackageMap packages;
+  bool logNonExisting;
+
+  FilePackageManagerData(void) : logNonExisting(true) {}
+
+  InputStream GetFile(std::string filename) {
+    for(unsigned int i = 0; i < filename.size(); ++i) {
+      if(filename[i] == '\\')
+        filename[i] = '/';
+    }
+
+    for(PackageMap::reverse_iterator it = packages.rbegin(); it != packages.rend(); ++it) {
+      InputStream result = it->second->GetFile(filename);
+      if(!result.IsEof())
+        return result;
+    }
+
+    // This is a bit of a hack.
+    // Fix all data to use only lowercase letters if you
+    // want it to work right. But you know me and upercase characters. --Allanis
+    for(unsigned int i = 0; i < filename.size(); ++i) {
+      // Not found try again in lowercase..
+      if(isupper(filename[i]))
+        filename[i] = tolower(filename[i]);
+    }
+
+    // Nothing has been found.
+    if(logNonExisting) {
+      Debug::logger->message("FilePackageManager::GetFile - File: \"%s\" does not exist or is zero in length!", filename.c_str());
+    }
+    InputStream inputStream;
+    boost::shared_ptr<EmptyBuffer> inputBuffer(new EmptyBuffer());
+
+    inputStream.SetBuffer(inputBuffer);
+    return inputStream;
+  }
+};
+
+FilePackageManager::FilePackageManager(void) {
+  boost::scoped_ptr<FilePackageManagerData> tempData(new FilePackageManagerData());
+  _data.swap(tempData);
+}
+
+FilePackageManager::~FilePackageManager(void) {
+}
+
+void FilePackageManager::AddPackage(boost::shared_ptr<IFilePackage> filePackage, int priority) {
+  std::pair<int, boost::shared_ptr<IFilePackage> > value(priority, filePackage);
+  _data->packages.insert(value);
+}
+
+boost::shared_ptr<IFileList> FilePackageManager::FindFiles(const std::string& dir, const std::string& extension, bool caseSensitive) {
+  boost::shared_ptr<IFileList> result(new FileList());
+  result->SetCaseSensitivity(caseSensitive);
+
+  for(PackageMap::iterator it = _data->packages.begin(); it != _data->packages.end(); ++it)
+    it->second->FindFiles(dir, extension, *result);
+  
+  return result;
+}
+
+InputStream FilePackageManager::GetFile(const std::string& filename) {
+  return _data->GetFile(filename);
+}
+
+void FilePackageManager::SetInputStreamErrorReporting(bool logNonExisting) {
+  // HACK: This goes directly to the input file stream...
+  _data->logNonExisting = logNonExisting;
+}
+
+FilePackageManager& FilePackageManager::GetInstance(void) {
+  if(!instancePtr)
+    instancePtr = &instance;
+  return *instancePtr;
+}
+
+void FilePackageManager::SetInstancePtr(FilePackageManager* newInstance) {
+  assert(newInstance);
+  instancePtr = newInstance;
+
+  //FilePackageManager& oldInstance = GetInstance();
+  //oldInstance._data->packages = newInstance->_data->packages;
+}
+
+} // Namespace filesystem.
+} // Namespace saracraft.
+
diff --git a/src/System/Filesystem/FilePackageManager.h b/src/System/Filesystem/FilePackageManager.h
new file mode 100644
index 0000000..30d3b77
--- /dev/null
+++ b/src/System/Filesystem/FilePackageManager.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include <boost/scoped_ptr.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include "IFilePackage.h"
+
+namespace saracraft {
+namespace filesystem {
+
+class IFileList;
+struct FilePackageManagerData;
+
+class FilePackageManager {
+  boost::scoped_ptr<FilePackageManagerData> _data;
+public:
+  FilePackageManager(void);
+  ~FilePackageManager(void);
+
+  void AddPackage(boost::shared_ptr<IFilePackage> filePackae, int priority);
+  boost::shared_ptr<IFileList> FindFiles(const std::string& dir, const std::string& extension, bool caseSensitive = false);
+  InputStream GetFile(const std::string& filename);
+
+  void SetInputStreamErrorReporting(bool logNonExisting);
+
+  static FilePackageManager& GetInstance(void);
+  static void SetInstancePtr(FilePackageManager* instance);
+};
+
+} // Namespace filesystem.
+} // Namespace saracraft.
+
diff --git a/src/System/Filesystem/IFilePackage.h b/src/System/Filesystem/IFilePackage.h
index eda9537..2cd54f3 100644
--- a/src/System/Filesystem/IFilePackage.h
+++ b/src/System/Filesystem/IFilePackage.h
@@ -10,7 +10,7 @@ public:
   virtual ~IFilePackage(void) {}
 
   virtual void FindFiles(const std::string& dir, const std::string& extension, IFileList& result) = 0;
-  virtual InputStream getFile(const std::string& filename) = 0;
+  virtual InputStream GetFile(const std::string& filename) = 0;
 };
 
 } // Namespace filesystem.
diff --git a/src/System/Filesystem/InputFileStream.cpp b/src/System/Filesystem/InputFileStream.cpp
new file mode 100644
index 0000000..27e659a
--- /dev/null
+++ b/src/System/Filesystem/InputFileStream.cpp
@@ -0,0 +1,122 @@
+#include <fstream>
+#include "../Debug.h"
+#include "InputFileStream.h"
+
+namespace saracraft {
+namespace filesystem {
+
+struct InputFileStreamBufferData {
+  FILE* fp;
+  size_t size;
+
+  InputFileStreamBufferData(const std::string filename) : fp(0), size(0) {
+    fp = fopen(filename.c_str(), "rb");
+
+#ifdef __UNIX__
+    // Another ugly as hell case sensitive hack.
+    // if anyone finds a nice way to handle this. Please implement it. -- Allanis
+    if(!fp) {
+      std::string filename = filename;
+      for(unsigned int i = 0; i < filename.size(); i++) {
+        if(isupper(filename[i]))
+          filename[i] = tolower(filename[i]);
+        else if(filename[i] == '\\')
+          filename[i] = '/';
+      }
+      fp = fopen(filename.c_str(), "rb");
+    }
+#endif
+    if(fp) {
+      fseek(fp, 0, SEEK_END);
+      size = ftell(fp);
+      fseek(fp, 0, SEEK_SET);
+    }
+    if(!size)
+      Close();
+  }
+
+  ~InputFileStreamBufferData(void) {
+    Close();
+  }
+
+  void Close(void) {
+    if(fp) {
+      fclose(fp);
+      fp = 0;
+    }
+  }
+};
+
+InputFileStreamBuffer::~InputFileStreamBuffer(void) {
+
+}
+
+unsigned char InputFileStreamBuffer::PopByte(void) {
+  char byte = 0;
+  if(_data->fp) {
+    int input = fgetc(_data->fp);
+    if(input == EOF)
+      _data->Close();
+    else
+      byte = (char)input;
+  }
+  return byte;
+}
+
+bool InputFileStreamBuffer::IsEof(void) const {
+  if(!_data->fp)
+    return true;
+
+  return false;
+}
+
+int InputFileStreamBuffer::GetSize(void) const {
+  if(!_data->fp)
+    return 0;
+
+  // This could cause maybe about a 2GB limimitation to file size
+  // by casting to int. Feel free to FIXME.
+  // -- Allanis
+  return int(_data->size);
+}
+
+void InputFileStreamBuffer::PopBytes(char* buffer, int bytes) {
+  if(!_data->fp) {
+    for(int i = 0; i < bytes; ++i)
+      buffer[i] = 0;
+  } else {
+    //_data->stream.read(buffer, bytes);
+    if(fread(buffer, 1, bytes, _data->fp) != (unsigned)bytes)
+      _data->Close();
+  }
+}
+
+// HACK: ffs. This is needed to get some sense into the input stream error reporting.
+//bool input_file_stream_no_nonexisting_error_message = false;
+
+//void SetInputStreamErrorReporting(bool logNonExisting) {
+//  input_file_stream_no_nonexisting_error_message = !logNonExisting;
+//}
+
+InputStream CreateInputFileStream(const std::string& filename) {
+  
+  // This whole method is pissing me off!!!!!!!!!!
+  //There..
+
+  //InputStream inputStream;
+  //boost::shared_ptr<InputFileStreamBuffer> inputBuffer(new InputFileStreamBuffer(filename));
+  // Eh.. No.
+  // TODO: Would need a seperate error check, eof is not the same as the file does not exist..
+  // This would just spam error messages. We don't want that.
+ /*if(!inputBuffer->IsEof()) {
+    if(!input_file_stream_no_nonexisting_error_message) {
+      Debug->logger("CreateInputFileStream - File \"%s\"does not exist or is zero length.", filename.c_str());
+    }
+  }*/
+  //inputStream.SetBuffer(inputBuffer);
+  //return inputStream;
+}
+
+} // Namespace filesystem.
+} // Namespace saracraft.
+
diff --git a/src/System/Filesystem/InputFileStream.h b/src/System/Filesystem/InputFileStream.h
new file mode 100644
index 0000000..7285ff2
--- /dev/null
+++ b/src/System/Filesystem/InputFileStream.h
@@ -0,0 +1,30 @@
+// I forgot some code..
+#pragma once
+#include <boost/scoped_ptr.hpp>
+#include "InputStream.h"
+
+namespace saracraft {
+namespace filesystem {
+
+struct InputFileStreamBufferData;
+
+class InputFileStreamBuffer: public IInputStreamBuffer {
+  boost::scoped_ptr<InputFileStreamBufferData> _data;
+
+public:
+  InputFileStreamBuffer(const std::string& filename);
+  ~InputFileStreamBuffer(void);
+
+  unsigned char PopByte(void);
+  bool IsEof(void) const;
+  int GetSize(void) const;
+
+  void PopBytes(char* buffer, int bytes);
+};
+
+InputStream CreateInputFileStream(const std::string& filename);
+void SetInputStreamErrorReporting(bool logNonExisting);
+
+} // Namespace filesystem.
+} // Namespace saracraft.
+