215 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			215 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // vim: set sts=2 ts=8 sw=2 tw=99 et:
 | |
| //
 | |
| // Copyright (C) 2012-2014 AlliedModders LLC, David Anderson
 | |
| //
 | |
| // This file is part of SourcePawn.
 | |
| //
 | |
| // SourcePawn is free software: you can redistribute it and/or modify it under
 | |
| // the terms of the GNU General Public License as published by the Free
 | |
| // Software Foundation, either version 3 of the License, or (at your option)
 | |
| // any later version.
 | |
| // 
 | |
| // SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
 | |
| // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 | |
| // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 | |
| //
 | |
| // You should have received a copy of the GNU General Public License along with
 | |
| // SourcePawn. If not, see http://www.gnu.org/licenses/.
 | |
| #ifndef _include_spcomp2_smx_builder_h_
 | |
| #define _include_spcomp2_smx_builder_h_
 | |
| 
 | |
| #include <am-string.h>
 | |
| #include <am-vector.h>
 | |
| #include <am-hashmap.h>
 | |
| #include <am-refcounting.h>
 | |
| #include <smx/smx-headers.h>
 | |
| #include "string-pool.h"
 | |
| #include "memory-buffer.h"
 | |
| 
 | |
| namespace ke {
 | |
| 
 | |
| // An SmxSection is a named blob of data.
 | |
| class SmxSection : public Refcounted<SmxSection>
 | |
| {
 | |
|  public:
 | |
|   SmxSection(const char *name)
 | |
|    : name_(name)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   virtual bool write(ISmxBuffer *buf) = 0;
 | |
|   virtual size_t length() const = 0;
 | |
| 
 | |
|   const AString &name() const {
 | |
|     return name_;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   AString name_;
 | |
| };
 | |
| 
 | |
| // An SmxBlobSection is a section that has some kind of header structure
 | |
| // (specified as a template parameter), and then an arbitrary run of bytes
 | |
| // immediately after.
 | |
| template <typename T>
 | |
| class SmxBlobSection : public SmxSection
 | |
| {
 | |
|  public:
 | |
|   SmxBlobSection(const char *name)
 | |
|    : SmxSection(name),
 | |
|      extra_(nullptr),
 | |
|      extra_len_(0)
 | |
|   {
 | |
|     memset(&t_, 0, sizeof(t_));
 | |
|   }
 | |
| 
 | |
|   T &header() {
 | |
|     return t_;
 | |
|   }
 | |
|   void setBlob(uint8_t *blob, size_t len) {
 | |
|     extra_ = blob;
 | |
|     extra_len_ = len;
 | |
|   }
 | |
|   bool write(ISmxBuffer *buf) KE_OVERRIDE {
 | |
|     if (!buf->write(&t_, sizeof(t_)))
 | |
|       return false;
 | |
|     if (!extra_len_)
 | |
|       return true;
 | |
|     return buf->write(extra_, extra_len_);
 | |
|   }
 | |
|   size_t length() const KE_OVERRIDE {
 | |
|     return sizeof(t_) + extra_len_;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   T t_;
 | |
|   uint8_t *extra_;
 | |
|   size_t extra_len_;
 | |
| };
 | |
| 
 | |
| // An SmxBlobSection without headers.
 | |
| template <>
 | |
| class SmxBlobSection<void> : public SmxSection
 | |
| {
 | |
|  public:
 | |
|   SmxBlobSection(const char *name)
 | |
|    : SmxSection(name)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   void add(void *bytes, size_t len) {
 | |
|     buffer_.write(bytes, len);
 | |
|   }
 | |
|   bool write(ISmxBuffer *buf) KE_OVERRIDE {
 | |
|     return buf->write(buffer_.bytes(), buffer_.size());
 | |
|   }
 | |
|   size_t length() const KE_OVERRIDE {
 | |
|     return buffer_.size();
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   MemoryBuffer buffer_;
 | |
| };
 | |
| 
 | |
| // An SmxListSection is a section that is a simple table of uniformly-sized
 | |
| // structures. It has no header of its own.
 | |
| template <typename T>
 | |
| class SmxListSection : public SmxSection
 | |
| {
 | |
|  public:
 | |
|   SmxListSection(const char *name)
 | |
|    : SmxSection(name)
 | |
|   {
 | |
|   }
 | |
| 
 | |
|   void append(const T &t) {
 | |
|     list_.append(t);
 | |
|   }
 | |
|   T &add() {
 | |
|     list_.append(T());
 | |
|     return list_.back();
 | |
|   }
 | |
|   bool write(ISmxBuffer *buf) KE_OVERRIDE {
 | |
|     return buf->write(list_.buffer(), list_.length() * sizeof(T));
 | |
|   }
 | |
|   size_t length() const KE_OVERRIDE {
 | |
|     return count() * sizeof(T);
 | |
|   }
 | |
|   size_t count() const {
 | |
|     return list_.length();
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   Vector<T> list_;
 | |
| };
 | |
| 
 | |
| // A name table is a blob of zero-terminated strings. Strings are entered
 | |
| // into the table as atoms, so duplicate stings are not emitted.
 | |
| class SmxNameTable : public SmxSection
 | |
| {
 | |
|  public:
 | |
|   SmxNameTable(const char *name)
 | |
|    : SmxSection(name),
 | |
|      buffer_size_(0)
 | |
|   {
 | |
|     name_table_.init(64);
 | |
|   }
 | |
| 
 | |
|   uint32_t add(StringPool &pool, const char *str) {
 | |
|     return add(pool.add(str));
 | |
|   }
 | |
| 
 | |
|   uint32_t add(Atom *str) {
 | |
|     NameTable::Insert i = name_table_.findForAdd(str);
 | |
|     if (i.found())
 | |
|       return i->value;
 | |
| 
 | |
|     assert(IsUint32AddSafe(buffer_size_, str->length() + 1));
 | |
| 
 | |
|     uint32_t index = buffer_size_;
 | |
|     name_table_.add(i, str, index);
 | |
|     names_.append(str);
 | |
|     buffer_size_ += str->length() + 1;
 | |
|     return index;
 | |
|   }
 | |
| 
 | |
|   bool write(ISmxBuffer *buf) KE_OVERRIDE;
 | |
|   size_t length() const KE_OVERRIDE {
 | |
|     return buffer_size_;
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   struct HashPolicy {
 | |
|     static uint32_t hash(Atom *str) {
 | |
|       return HashPointer(str);
 | |
|     }
 | |
|     static bool matches(Atom *a, Atom *b) {
 | |
|       return a == b;
 | |
|     }
 | |
|   };
 | |
|   typedef HashMap<Atom *, size_t, HashPolicy> NameTable;
 | |
| 
 | |
|   NameTable name_table_;
 | |
|   Vector<Atom *> names_;
 | |
|   uint32_t buffer_size_;
 | |
| };
 | |
| 
 | |
| class SmxBuilder
 | |
| {
 | |
|  public:
 | |
|   SmxBuilder();
 | |
| 
 | |
|   bool write(ISmxBuffer *buf);
 | |
| 
 | |
|   void add(const Ref<SmxSection> §ion) {
 | |
|     sections_.append(section);
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   Vector<Ref<SmxSection>> sections_;
 | |
| };
 | |
| 
 | |
| } // namespace ke
 | |
| 
 | |
| #endif // _include_spcomp2_smx_builder_h_
 |