Commits

Braden Obrzut committed a23b7b1

- Added a byte stream class and then removed all uses of STL (except for fileio in main).
- Added documentation for new translationrange3 opcode and 3 new ACSF functions.

  • Participants
  • Parent commits 174567f

Comments (0)

Files changed (15)

docs/manual.odt

Binary file modified.

src/CMakeLists.txt

 
 add_executable(accpp
 	lib/hashmap.cpp
+	lib/stream.cpp
 	lib/string.cpp
 	assembler.cpp
 	compiler.cpp

src/assembler.cpp

 #include "scanner.h"
 #include "lib/hashmap.h"
 #include "lib/linkedlist.h"
-#include "lib/map.h"
+#include "lib/stream.h"
 #include "lib/string.h"
 
 #include <cstring>
-#include <sstream>
 
-using namespace std;
 using namespace ACCPP;
 
 // Instructions ----------------------------------------------------------------
 	Parse(sc);
 	Optimize();
 
-	stringstream out(ios_base::out|ios_base::binary);
+	Stream out;
 	// Write header.
 	code[CODE_HEAD]->PushOffset(8);
 	unsigned int size = GetByteCodeSize()+8;
 			header[11] = 'E';
 			break;
 	}
-	out.write(header, 8);
+	out.Write(header, 8);
 
 	ByteCode *pCode = code[CODE_HEAD];
 	while(pCode->OpCode() != NULL)
 		if(g_format == FORMAT_ZDOOM)
 		{
 			if(pCode->OpCode()->opcode < 240)
-				out.write(data, 1);
+				out.Write(data, 1);
 			else
 			{
 				unsigned int opcode = pCode->OpCode()->opcode;
 				opcode = (((opcode - 240)>>8) + 240) + (((opcode - 240)&0xFF)<<8);
 				WriteLittleShort(data, opcode);
-				out.write(data, 2);
+				out.Write(data, 2);
 			}
 		}
 		else
-			out.write(data, 4);
+			out.Write(data, 4);
 
 		if(pCode->GetNumArguments() > 0)
 		{
 			if(*type == '+')
 			{
 				++type;
-				if(out.tellp()%4 != 0)
+				if(out.Size()%4 != 0)
 				{
 					WriteLittleLong(data, 0);
-					out.write(data, 4 - (out.tellp()%4));
+					out.Write(data, 4 - (out.Size()%4));
 				}
 			}
 			for(unsigned int i = 0;i < pCode->GetNumArguments();i++)
 				switch(lastType)
 				{
 					default:
-						out.write(data, 4);
+						out.Write(data, 4);
 						break;
 					case 'S':
-						out.write(data, 2);
+						out.Write(data, 2);
 						break;
 					case 'B':
-						out.write(data, 1);
+						out.Write(data, 1);
 						break;
 				}
 			}
 		// Write directory.
 		char directoryHeader[4];
 		WriteLittleLong(directoryHeader, scripts.Size());
-		out.write(directoryHeader, 4);
+		out.Write(directoryHeader, 4);
 		for(LinkedList<Script>::ConstIterator iter(scripts);iter.Next();)
 		{
 			int number = iter->number + (iter->type*1000);
 				sc.ScriptMessage(Scanner::ERROR, "Address \"%s\" for script %d unresolved.", iter->address.Chars(), iter->number);
 			char scriptPtr[12] = {WriteLittleLongDirect(number), 0,0,0,0, WriteLittleLongDirect(args)};
 			WriteLittleLong(scriptPtr+4, address->Resolve(this));
-			out.write(scriptPtr, 12);
+			out.Write(scriptPtr, 12);
 		}
 
 		// Write strings table.
-		GetStringTableSize(stringTable, static_cast<unsigned int> (out.tellp()) + 4*(stringTable.Size()+1));
+		GetStringTableSize(stringTable, static_cast<unsigned int> (out.Size()) + 4*(stringTable.Size()+1));
 		WriteStringTable(out, stringTable);
 	}
 	else
 			unsigned int numScriptsWithVarCount = 0;
 			unsigned int numScriptsWithFlags = 0;
 			WriteLittleLong(chunkHeader+4, scripts.Size()*8);
-			out.write(chunkHeader, 8);
+			out.Write(chunkHeader, 8);
 			for(LinkedList<Script>::ConstIterator iter(scripts);iter.Next();)
 			{
 				const Constant *address = ResolveLabel(iter->address);
 				char sptr[8] = {0,0, (unsigned char)iter->type, (unsigned char)iter->args, 0,0,0,0};
 				WriteLittleShort(sptr, iter->number);
 				WriteLittleLong(sptr+4, address->Resolve(this));
-				out.write(sptr, 8);
+				out.Write(sptr, 8);
 
 				if(iter->flags != 0)
 					numScriptsWithFlags++;
 			{
 				memcpy(chunkHeader, "SFLG", 4);
 				WriteLittleLong(chunkHeader+4, numScriptsWithFlags*4);
-				out.write(chunkHeader, 8);
+				out.Write(chunkHeader, 8);
 				for(LinkedList<Script>::ConstIterator iter(scripts);iter.Next();)
 				{
 					if(iter->flags == 0)
 						continue;
 
 					char data[4] = {WriteLittleShortDirect(iter->number), WriteLittleShortDirect(iter->flags)};
-					out.write(data, 4);
+					out.Write(data, 4);
 				}
 			}
 
 			{
 				memcpy(chunkHeader, "SVCT", 4);
 				WriteLittleLong(chunkHeader+4, numScriptsWithVarCount*4);
-				out.write(chunkHeader, 8);
+				out.Write(chunkHeader, 8);
 				for(LinkedList<Script>::ConstIterator iter(scripts);iter.Next();)
 				{
 					if(iter->varCount == 20)
 						continue;
 
 					char data[4] = {WriteLittleShortDirect(iter->number), WriteLittleShortDirect(iter->varCount)};
-					out.write(data, 4);
+					out.Write(data, 4);
 				}
 			}
 
 				memcpy(chunkHeader, "SNAM", 4);
 				unsigned int strPointersSize = 4*scriptNames.Size();
 				WriteLittleLong(chunkHeader+4, 4+strPointersSize+GetStringTableSize(scriptNames, 4+strPointersSize));
-				out.write(chunkHeader, 8);
+				out.Write(chunkHeader, 8);
 				WriteStringTable(out, scriptNames);
 			}
 		}
 			if(g_encryptStrings)
 				chunkHeader[3] = 'E';
 			WriteLittleLong(chunkHeader+4, 12+strPointersSize+GetStringTableSize(stringTable, 12+strPointersSize));
-			out.write(chunkHeader, 8);
+			out.Write(chunkHeader, 8);
 			WriteStringTable(out, stringTable, true, g_encryptStrings);
 		}
 
 			for(LinkedList<String>::ConstIterator iter(loadImports);iter.Next();)
 				size += iter->Length()+1;
 			WriteLittleLong(chunkHeader+4, size);
-			out.write(chunkHeader, 8);
+			out.Write(chunkHeader, 8);
 			for(LinkedList<String>::ConstIterator iter(loadImports);iter.Next();)
-				out.write(iter->Chars(), iter->Length()+1);
+				out.Write(iter->Chars(), iter->Length()+1);
 		}
 
 		// Functions
 			StringTable functionNames;
 			memcpy(chunkHeader, "FUNC", 4);
 			WriteLittleLong(chunkHeader+4, functions.Size()*8);
-			out.write(chunkHeader, 8);
+			out.Write(chunkHeader, 8);
 			for(LinkedList<Function>::ConstIterator iter(functions);iter.Next();)
 			{
 				const Constant *address = ResolveLabel(iter->address);
 					sc.ScriptMessage(Scanner::ERROR, "Function \"%s\" undefined.", iter->address.Chars());
 				char data[8] = {(unsigned char)iter->numArgs,(unsigned char)iter->numVars,iter->hasReturn,0, 0,0,0,0};
 				WriteLittleLong(data+4, address->Resolve());
-				out.write(data, 8);
+				out.Write(data, 8);
 				StringTableObject strObj;
 				strObj.str = iter->label;
 				functionNames.Push(strObj);
 			memcpy(chunkHeader, "FNAM", 4);
 			unsigned int strPointersSize = 4*functionNames.Size();
 			WriteLittleLong(chunkHeader+4, 4+strPointersSize+GetStringTableSize(functionNames, 4+strPointersSize));
-			out.write(chunkHeader, 8);
+			out.Write(chunkHeader, 8);
 			WriteStringTable(out, functionNames);
 		}
 
 
 				memcpy(chunkHeader, "AINI", 4);
 				WriteLittleLong(chunkHeader+4, (iter->size+1)*4);
-				out.write(chunkHeader, 8);
+				out.Write(chunkHeader, 8);
 				char* data = new char[(iter->size+1)*4];
 				char* tmp = data+4;
 				WriteLittleLong(data, iter->number);
 					WriteLittleLong(tmp, citer->Resolve(this));
 					tmp += 4;
 				}
-				out.write(data, (iter->size+1)*4);
+				out.Write(data, (iter->size+1)*4);
 				delete[] data;
 			}
 
 			{
 				memcpy(chunkHeader, "ARAY", 4);
 				WriteLittleLong(chunkHeader+4, arrayChunkSizes[0]);
-				out.write(chunkHeader, 8);
+				out.Write(chunkHeader, 8);
 				for(LinkedList<MapArray>::ConstIterator iter(mapArrays);iter.Next();)
 				{
 					if(iter->import)
 						continue;
 					char data[8] = {WriteLittleLongDirect(iter->number), WriteLittleLongDirect(iter->size)};
-					out.write(data, 8);
+					out.Write(data, 8);
 				}
 			}
 
 			{
 				memcpy(chunkHeader, "AIMP", 4);
 				WriteLittleLong(chunkHeader+4, arrayChunkSizes[1]);
-				out.write(chunkHeader, 8);
+				out.Write(chunkHeader, 8);
 				char numArrayImportsOut[4] = {WriteLittleLongDirect(numArrayImports)};
-				out.write(numArrayImportsOut, 4);
+				out.Write(numArrayImportsOut, 4);
 				for(LinkedList<MapArray>::ConstIterator iter(mapArrays);iter.Next();)
 				{
 					if(!iter->import)
 						continue;
 					char data[8] = {WriteLittleLongDirect(iter->number), WriteLittleLongDirect(iter->size)};
-					out.write(data, 8);
-					out.write(iter->label.Chars(), iter->label.Length()+1);
+					out.Write(data, 8);
+					out.Write(iter->label.Chars(), iter->label.Length()+1);
 				}
 			}
 
 			{
 				memcpy(chunkHeader, "ASTR", 4);
 				WriteLittleLong(chunkHeader+4, numStringArrays*4);
-				out.write(chunkHeader, 8);
+				out.Write(chunkHeader, 8);
 				for(LinkedList<MapArray>::ConstIterator iter(mapArrays);iter.Next();)
 				{
 					if(iter->import || !iter->strings)
 						continue;
 					char data[4] = {WriteLittleLongDirect(iter->number)};
-					out.write(data, 4);
+					out.Write(data, 4);
 				}
 			}
 		}
 			{
 				memcpy(chunkHeader, "MINI", 4);
 				WriteLittleLong(chunkHeader+4, (varEnd-varStart+2)*4);
-				out.write(chunkHeader, 8);
+				out.Write(chunkHeader, 8);
 				char* data = new char[varStart];
 				WriteLittleLong(data, varEnd-varStart+1);
 				for(LinkedList<MapVariable>::ConstIterator iter(mapVariables);iter.Next();)
 				{
 					WriteLittleLong(data+4+(iter->number - varStart), iter->value.Resolve(this));
 				}
-				out.write(data, (varEnd-varStart+2)*4);
+				out.Write(data, (varEnd-varStart+2)*4);
 				delete[] data;
 			}
 
 			{
 				memcpy(chunkHeader, "MIMP", 4);
 				WriteLittleLong(chunkHeader+4, importChunkSize);
-				out.write(chunkHeader, 8);
+				out.Write(chunkHeader, 8);
 				for(LinkedList<MapVariable>::ConstIterator iter(mapVariables);iter.Next();)
 				{
 					if(!iter->import)
 						continue;
 					char data[4] = {WriteLittleLongDirect(iter->number)};
-					out.write(data, 4);
-					out.write(iter->label.Chars(), iter->label.Length()+1);
+					out.Write(data, 4);
+					out.Write(iter->label.Chars(), iter->label.Length()+1);
 				}
 			}
 
 			{
 				memcpy(chunkHeader, "MSTR", 4);
 				WriteLittleLong(chunkHeader+4, numStringVars*4);
-				out.write(chunkHeader, 8);
+				out.Write(chunkHeader, 8);
 				for(LinkedList<MapVariable>::ConstIterator iter(mapVariables);iter.Next();)
 				{
 					if(iter->import || !iter->isString)
 						continue;
 					char data[4] = {WriteLittleLongDirect(iter->number)};
-					out.write(data, 4);
+					out.Write(data, 4);
 				}
 			}
 		}
 			unsigned int strPointersSize = 4*mapNameTable.Size();
 			memcpy(chunkHeader, "MEXP", 4);
 			WriteLittleLong(chunkHeader+4, 4+strPointersSize+GetStringTableSize(mapNameTable, 4+strPointersSize));
-			out.write(chunkHeader, 8);
+			out.Write(chunkHeader, 8);
 			WriteStringTable(out, mapNameTable);
 		}
 
-		unsigned int newHeaderOffset = static_cast<unsigned int> (out.tellp())+8;
-		out.write(header+8, 16);
+		unsigned int newHeaderOffset = static_cast<unsigned int> (out.Size())+8;
+		out.Write(header+8, 16);
 		WriteLittleLong(header+4, newHeaderOffset);
-		out.seekp(4, ios_base::beg);
-		out.write(header+4, 4);
+		out.Seek(4);
+		out.Write(header+4, 4);
 	}
 
-	return out.str().c_str();
+	return String(out.Data(), out.Size());
 }
 
 unsigned int Assembler::GetByteCodeSize() const
 	return labelIndex.Find(label);
 }
 
-void Assembler::WriteStringTable(std::stringstream &out, StringTable &table, bool wasteful, bool encrypt)
+void Assembler::WriteStringTable(Stream &out, StringTable &table, bool wasteful, bool encrypt)
 {
 	char header[12] = {0,0,0,0, WriteLittleLongDirect(table.Size()), 0,0,0,0};
 	if(wasteful)
-		out.write(header, 12);
+		out.Write(header, 12);
 	else
-		out.write(header+4, 4);
+		out.Write(header+4, 4);
 
 	char* data = new char[table.Size()*4];
 	unsigned int pos = 0;
 		WriteLittleLong(data+pos, iter->offset);
 		pos += 4;
 	}
-	out.write(data, table.Size()*4);
+	out.Write(data, table.Size()*4);
 	delete[] data;
 	for(StringTable::Iterator iter(table);iter.Next();)
 	{
 		if(encrypt)
-			out.write(iter->str.EncryptedChars(iter->offset), iter->str.Length()+1);
+			out.Write(iter->str.EncryptedChars(iter->offset), iter->str.Length()+1);
 		else
-			out.write(iter->str.Chars(), iter->str.Length()+1);
+			out.Write(iter->str.Chars(), iter->str.Length()+1);
 	}
 }
 #include "lib/linkedlist.h"
 #include "lib/string.h"
 
-#include <sstream>
-
 class Scanner;
+namespace ACCPP { class Stream; }
 
 class Assembler
 {
 
 		// Use GetStringTableSize to assign offsets to the string table.
 		static unsigned int	GetStringTableSize(StringTable &table, unsigned int offset);
-		static void			WriteStringTable(std::stringstream &out, StringTable &table, bool wasteful=false, bool encrypt=false);
+		static void			WriteStringTable(ACCPP::Stream &out, StringTable &table, bool wasteful=false, bool encrypt=false);
 
 		enum
 		{
 #include "lib/string.h"
 
 #include <cstdio>
-#include <iostream>
-#include <sstream>
 
-using namespace std;
 using namespace ACCPP;
 
-Compiler::Compiler() : out(ios_base::out), currentScope(0)
+Compiler::Compiler() : currentScope(0)
 {
 	types = new TypeHierarchy();
 }
 String Compiler::Compile(Scanner &sc)
 {
 	// Clear
-	out.str("");
+	out.Clear();
 
 	while(sc.TokensLeft())
 	{
 
 	DumpStringTable();
 
-	return out.str().c_str();
+	return String(out.Data(), out.Size());
 }
 
 void Compiler::DumpStringTable()
 
 String Compiler::ParseAssemblyBlock(Scanner &sc)
 {
-	stringstream out;
+	Stream out;
 
 	sc.MustGetToken('{');
 	unsigned int blockStart = sc.GetScanPos();
 		{
 			if(levelCounter == 0)
 			{
-				out << string(sc.GetData()+blockStart, blockEnd-blockStart) << "\n";
+				out << String(sc.GetData()+blockStart, blockEnd-blockStart) << "\n";
 				break;
 			}
 			levelCounter--;
 	}
 	while(sc.TokensLeft());
 
-	return out.str().c_str();
+	return String(out.Data(), out.Size());
 }
 
 String Compiler::ParseScript(Scanner &sc)
 	unsigned int localVar = 0;
 	Symbol *localSymbol;
 
-	stringstream out;
+	Stream out;
 
 	sc.MustGetToken('{');
 	while(!sc.CheckToken('}'))
 			out << localSymbol->AssignSymbol() << "\n";
 	}
 
-	return out.str().c_str();
+	return String(out.Data(), out.Size());
 }
 
 void Compiler::PopScope()
 #define __COMPILER_H__
 
 #include "lib/hashmap.h"
+#include "lib/stream.h"
 #include "lib/string.h"
 
-#include <sstream>
-
 class Scanner;
-
 class ExpressionNode;
 class Symbol;
 class TypeHierarchy;
 		void			PopScope();
 		void			PushScope();
 
-		std::stringstream	out;
+		ACCPP::Stream	out;
 
 		unsigned int currentScope;
 		ACCPP::HashMap<ACCPP::String, ACCPP::String> stringTable;

src/disassembler.cpp

 #include "preprocessor.h"
 #include "scanner.h"
 #include "lib/linkedlist.h"
+#include "lib/stream.h"
 #include "lib/string.h"
 
-#include <sstream>
-
-using namespace std;
 using namespace ACCPP;
 
 // --- So this is the only file we need binary reading functions. --------------
 		unsigned short	flags;
 		unsigned short	varCount;
 
-		void	WritePointer(stringstream &out)
+		void	WritePointer(Stream &out)
 		{
 			out << number << " " << type << " " << argCount << " " << "Script" << number;
 			if(varCount != 20)
 	this->data = data;
 	this->size = size;
 
-	stringstream out(ios_base::out);
+	Stream out;
 	out << "// Disassembled by ACC++\n#include \"mnemonics.inc\"\n\n";
 
 	// Detect format.
 		disassembledRanges.Push(range);
 	}
 
-	return out.str().c_str();
+	out.Write("", 1);
+	return out.Data();
 }
 
 bool Disassembler::FindInstruction(unsigned int code, Instruction &instr) const

src/expression.cpp

 
 #include <cassert>
 #include <cstdio>
-#include <sstream>
 
-using namespace std;
 using namespace ACCPP;
 
 static LabelGen expressionLabel("Expr");
 		symbol->GetType() == term[1]->GetType();
 }
 
-void ExpressionNode::DumpExpression(stringstream &out, String endLabel) const
+void ExpressionNode::DumpExpression(Stream &out, String endLabel) const
 {
 	TypeRef argumentTypes[2];
 	bool writeEndLabel = false;
 	{
 		if(op->operands == 3) // Ternary
 		{
-			string elsePoint = expressionLabel.Generate().Chars();
-			string endPoint = expressionLabel.Generate().Chars();
+			String elsePoint = expressionLabel.Generate();
+			String endPoint = expressionLabel.Generate();
 
 			out << op->instruction << " " << elsePoint << "\n";
 			if(term[1] != NULL)
 	return function ? function->GetReturnType().GetType() : argumentTypes[0].GetType();
 }
 
-ExpressionNode *ExpressionNode::ParseExpression(Compiler &compiler, Scanner &sc, stringstream &out, ExpressionNode *root, unsigned char opLevel)
+ExpressionNode *ExpressionNode::ParseExpression(Compiler &compiler, Scanner &sc, Stream &out, ExpressionNode *root, unsigned char opLevel)
 {
 	// We can't back out of our level in this recursion
 	if(root == NULL)
 
 #include "lib/string.h"
 
-#include <sstream>
-
 class Compiler;
 struct ExpressionOperator;
 class Scanner;
 class Symbol;
 class Type;
+namespace ACCPP { class Stream; }
 
 class ExpressionNode
 {
 	public:
 		~ExpressionNode();
 
-		void	DumpExpression(std::stringstream &out, ACCPP::String endLabel=ACCPP::String()) const;
+		void	DumpExpression(ACCPP::Stream &out, ACCPP::String endLabel=ACCPP::String()) const;
 
-		static ExpressionNode	*ParseExpression(Compiler &compiler, Scanner &sc, std::stringstream &out, ExpressionNode *root=NULL, unsigned char opLevel=255);
+		static ExpressionNode	*ParseExpression(Compiler &compiler, Scanner &sc, ACCPP::Stream &out, ExpressionNode *root=NULL, unsigned char opLevel=255);
 	protected:
 		enum ValueType
 		{

src/lib/hashmap.h

 		typename Chain::ConstIterator iter;
 	};
 
+	HashMap() : size(0) {}
+
 	void Delete(Iterator &position)
 	{
 		position.currentChain->Delete(position.iter);

src/lib/stream.cpp

+/*
+** Copyright (c) 2012, Braden "Blzut3" Obrzut
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * The names of its contributors may be used to endorse or promote
+**       products derived from this software without specific prior written
+**       permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+** INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "lib/stream.h"
+
+#include <cstring>
+#include <cstdio>
+
+using namespace ACCPP;
+
+#define STREAM_BLOCK_SIZE 2048
+
+Stream::Stream() : maxSize(STREAM_BLOCK_SIZE), size(0), position(0)
+{
+	bytes = new unsigned char[maxSize];
+}
+
+Stream::~Stream()
+{
+	delete[] bytes;
+}
+
+void Stream::Clear()
+{
+	size = 0;
+	position = 0;
+}
+
+void Stream::CheckBuffer(unsigned int length)
+{
+	if(position + length > maxSize)
+		Expand(size + length);
+}
+
+void Stream::Expand(unsigned int requestSize)
+{
+	const unsigned char* const old = bytes;
+	const unsigned int oldSize = maxSize;
+
+	maxSize = (requestSize/STREAM_BLOCK_SIZE + 1)*STREAM_BLOCK_SIZE;
+	bytes = new unsigned char[maxSize + STREAM_BLOCK_SIZE];
+	memcpy(bytes, old, oldSize);
+	delete[] old;
+}
+
+void Stream::IncrementPos(unsigned int length)
+{
+	position += length;
+	if(position > size)
+		size = position;
+}
+
+void Stream::Seek(unsigned int pos)
+{
+	position = pos;
+}
+
+void Stream::Write(const char* data, int length)
+{
+	if(length < 0)
+		length = strlen(data);
+
+	CheckBuffer(length);
+
+	memcpy(bytes+position, data, length);
+
+	IncrementPos(length);
+}
+
+void Stream::Write(int number)
+{
+	char buffer[12];
+	sprintf(buffer, "%d", number);
+	Write(buffer, strlen(buffer));
+}
+/*
+** Copyright (c) 2012, Braden "Blzut3" Obrzut
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * The names of its contributors may be used to endorse or promote
+**       products derived from this software without specific prior written
+**       permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+** ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT,
+** INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __ACCPP_STREAM_H__
+#define __ACCPP_STREAM_H__
+
+namespace ACCPP {
+
+/* Binary data stream.
+ */
+class Stream
+{
+public:
+	Stream();
+	~Stream();
+
+	void Clear();
+	const char* Data() const { return reinterpret_cast<const char*>(bytes); }
+	void Seek(unsigned int pos);
+	unsigned int Size() const { return size; }
+	void Write(const char* data, int length=-1);
+	void Write(int number);
+
+	inline Stream &operator<<(int number) { Write(number); return *this; }
+	inline Stream &operator<<(const char* str) { Write(str); return *this; }
+private:
+	void CheckBuffer(unsigned int length);
+	void IncrementPos(unsigned int length);
+	void Expand(unsigned int requestSize);
+
+	unsigned char* bytes;
+	unsigned int maxSize;
+	unsigned int size;
+	unsigned int position;
+};
+
+}
+
+#endif
 
 #include <iostream>
 #include <fstream>
-#include <sstream>
 #include <cstdarg>
 #include <cstdlib>
 #include <cstring>
 #include "main.h"
 #include "preprocessor.h"
 #include "lib/linkedlist.h"
+#include "lib/stream.h"
 #include "lib/string.h"
 
 using namespace std;
 	// If the file is "-" read from stdin
 	if(strcmp(filename, "-") == 0)
 	{
-		stringstream tmp(stringstream::out|stringstream::binary);
+		Stream tmp;
 		char buffer[1024];
-		streamsize inSize = 0;
 		while(true)
 		{
 			cin.get(buffer, 1024, '\0');
 			if(buffer[0] == '\0')
 				break;
-			tmp.write(buffer, strlen(buffer));
+			tmp.Write(buffer, strlen(buffer));
 		}
-		size = tmp.tellp();
+		size = tmp.Size();
 		char* inBuffer = new char[size+1];
-		strcpy(inBuffer, tmp.str().c_str());
+		memcpy(inBuffer, tmp.Data(), size);
 		inBuffer[size] = 0;
 		return inBuffer;
 	}
 
 	if(outFile == NULL)
 	{
-		string inFilename = inFile;
-		int ext = inFilename.find_last_of('.');
-		if(ext == string::npos)
+		String inFilename = inFile;
+		int ext = inFilename.LastIndexOf('.');
+		if(ext == -1)
 		{
-			deleteFile = new char[inFilename.length()+3];
+			deleteFile = new char[inFilename.Length()+3];
 			strcpy(deleteFile, inFile);
 		}
 		else
 		{
-			inFilename = inFilename.substr(0, ext);
-			deleteFile = new char[inFilename.length()+3];
-			strcpy(deleteFile, inFilename.c_str());
+			inFilename = inFilename.Substr(0, ext);
+			deleteFile = new char[inFilename.Length()+3];
+			strcpy(deleteFile, inFilename.Chars());
 		}
 		strcat(deleteFile, ".o");
 		outFile = deleteFile;

src/preprocessor.cpp

 */
 
 #include <cstring>
-#include <sstream>
 
 #include "main.h"
 #include "preprocessor.h"
 #include "scanner.h"
 #include "lib/stack.h"
+#include "lib/stream.h"
 #include "lib/string.h"
 
-using namespace std;
 using namespace ACCPP;
 
 typedef HashMap<String, const DefineConstant>::ConstIterator DefineIterator;
 			{
 				for(short i = 0;i < numVars;i++)
 				{
-					if(string((const char*)sc->str).compare(varList[i]) == 0)
+					if(sc->str.Compare(varList[i]) == 0)
 					{
 						Replace r;
 						r.position = sc.GetPos() + offset - sc->str.Length();
 {
 	if(numVars != 0 && parameters != NULL)
 	{
-		string out(replacement);
+		String out(replacement);
 		int offset = 0;
 		for(LinkedList<Replace>::ConstIterator iter = replaces.HeadConst();iter.Next();)
 		{
-			out.replace(iter->position + offset, iter->length, parameters[iter->index]);
+			out.Replace(iter->position + offset, iter->length, parameters[iter->index]);
 			offset += strlen(parameters[iter->index]) - iter->length;
 		}
-		return out.c_str();
+		return out;
 	}
 	return replacement;
 }
 	bool isASM = (item != NULL);
 
 	const char* inBuffer = ReadFile(filename);
-	string in = inBuffer;
+	String in = inBuffer;
 	delete[] inBuffer;
 
 	// First we want to normalize the line endings.  We'll use UNIX style.
-	for(int i = 0;(i = in.find("\n\r", i)) != string::npos;)
-		in.replace(i, 2, "\n");
-	for(int i = 0;(i = in.find('\r', i)) != string::npos;)
-		in.replace(i++, 1, 1, '\n');
+	for(int i = 0;(i = in.IndexOf("\n\r", i)) != -1;)
+		in.Replace(i, 2, "\n");
+	for(int i = 0;(i = in.IndexOf('\r', i)) != -1;)
+		in.Replace(i++, 1, "\n");
 
 	// We'll use a stringstream to make life a little easier.
-	stringstream out(ios_base::out);
-	Scanner sc(in.c_str(), in.length());
+	Stream out;
+	Scanner sc(in.Chars(), in.Length());
 	sc.SetScriptIdentifier(filename);
 	sc.GetNextToken();
 
 					out << "/*meta:" << filename << ":" << setLine << "*/";
 					setLine = 0;
 				}
-				out << in.substr(pos, sc.GetPos()-pos-1);
+				out << in.Substr(pos, sc.GetPos()-pos-1);
 			}
 
 			sc.MustGetToken(TK_Identifier);
-			if(string((const char*)sc->str).compare("define") == 0)
+			if(sc->str.Compare("define") == 0)
 			{
 				sc.MustGetToken(TK_Identifier);
 				String name = sc->str;
 									case ',':
 										paramEnd = sc.GetPos()-1;
 										paramList[numParameters] = new char[paramEnd-paramStart+1];
-										strcpy(paramList[numParameters], in.substr(paramStart, paramEnd-paramStart).c_str());
+										strcpy(paramList[numParameters], in.Substr(paramStart, paramEnd-paramStart).Chars());
 										numParameters++;
 										if(numParameters > item->GetNumParameters())
 											sc.ScriptMessage(Scanner::ERROR, "Macro %s only takes %d parameters.", itemKey.Chars(), item->GetNumParameters());
 						FinishParameters:
 							if(numParameters != item->GetNumParameters())
 								sc.ScriptMessage(Scanner::ERROR, "Macro %s requires %d parameters, but got %d instead.", itemKey.Chars(), item->GetNumParameters(), numParameters); 
-							out << in.substr(pos, macroStart-pos-itemKey.Length()) << item->DoReplace(paramList);
+							out << in.Substr(pos, macroStart-pos-itemKey.Length()) << item->DoReplace(paramList);
 							for(int i = 0;i < item->GetNumParameters();i++)
 								delete[] paramList[i];
 							delete[] paramList;
 						}
 						else
-							out << in.substr(pos, sc.GetPos()-pos-itemKey.Length()) << item->DoReplace(NULL);
+							out << in.Substr(pos, sc.GetPos()-pos-itemKey.Length()) << item->DoReplace(NULL);
 						pos = sc.GetPos();
 					}
 				}
 	}
 
 	if(pos != sc.GetPos())
-		out << in.substr(pos);
+		out << in.Substr(pos);
 
 	// Dump some ASM for libraries
 	if(dumpImports && importList.Size() > 0)
 			out << "\n";
 	}
 
-	return out.str().c_str();
+	out.Write("", 1);
+	return out.Data();
 }
 #include "lib/string.h"
 
 #include <cassert>
-#include <sstream>
+#include <cstdio>
 
-using namespace std;
 using namespace ACCPP;
 
 Type::Type(const String &name, const Type *parent) : parent(parent), status(FORWARD), name(name)
 String Symbol::AssignSymbol() const
 {
 	static const char* const instructions[7] = {"assignscriptvar", "assignmapvar", "assignworldvar", "assignglobalvar", "assignmaparray", "assignworldarray", "assignglobalarray"};
-	stringstream ss;
-	ss << instructions[scope];
-	ss << " ";
-	ss << local;
-	return ss.str().c_str();
+	char buffer[64];
+	sprintf(buffer, "%s %d", instructions[scope], local);
+	return buffer;
 }
 
 String Symbol::CallFunction() const
 {
 	assert(IsFunction());
 
-	stringstream ss;
-	ss << "call " << local;
-	return ss.str().c_str();
+	char buffer[64];
+	sprintf(buffer, "call %d", local);
+	return buffer;
 }
 
 String Symbol::PushSymbol() const
 {
 	static const char* const instructions[7] = {"pushscriptvar", "pushmapvar", "pushworldvar", "pushglobalvar", "pushmaparray", "pushworldarray", "pushglobalarray"};
-	stringstream ss;
-	ss << instructions[scope];
-	ss << " ";
-	ss << local;
-	return ss.str().c_str();
+	char buffer[64];
+	sprintf(buffer, "%s %d", instructions[scope], local);
+	return buffer;
 }