Merge remote-tracking branch 'origin/kitkat-dev'
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..9549a01
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,287 @@
+BASE_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# We default to release for the Android build system. Developers debugging
+# code can build with "Debug"
+GYP_CONFIGURATION := Release
+
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := libsfntly
+LOCAL_MODULE_SUFFIX := .a
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_GENERATED_SOURCES :=
+
+LOCAL_SRC_FILES := \
+	cpp/src/sfntly/data/byte_array.cc \
+	cpp/src/sfntly/data/font_data.cc \
+	cpp/src/sfntly/data/font_input_stream.cc \
+	cpp/src/sfntly/data/font_output_stream.cc \
+	cpp/src/sfntly/data/growable_memory_byte_array.cc \
+	cpp/src/sfntly/data/memory_byte_array.cc \
+	cpp/src/sfntly/data/readable_font_data.cc \
+	cpp/src/sfntly/data/writable_font_data.cc \
+	cpp/src/sfntly/font.cc \
+	cpp/src/sfntly/font_factory.cc \
+	cpp/src/sfntly/port/file_input_stream.cc \
+	cpp/src/sfntly/port/lock.cc \
+	cpp/src/sfntly/port/memory_input_stream.cc \
+	cpp/src/sfntly/port/memory_output_stream.cc \
+	cpp/src/sfntly/table/bitmap/big_glyph_metrics.cc \
+	cpp/src/sfntly/table/bitmap/bitmap_glyph.cc \
+	cpp/src/sfntly/table/bitmap/bitmap_glyph_info.cc \
+	cpp/src/sfntly/table/bitmap/bitmap_size_table.cc \
+	cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.cc \
+	cpp/src/sfntly/table/bitmap/ebdt_table.cc \
+	cpp/src/sfntly/table/bitmap/eblc_table.cc \
+	cpp/src/sfntly/table/bitmap/ebsc_table.cc \
+	cpp/src/sfntly/table/bitmap/glyph_metrics.cc \
+	cpp/src/sfntly/table/bitmap/index_sub_table.cc \
+	cpp/src/sfntly/table/bitmap/index_sub_table_format1.cc \
+	cpp/src/sfntly/table/bitmap/index_sub_table_format2.cc \
+	cpp/src/sfntly/table/bitmap/index_sub_table_format3.cc \
+	cpp/src/sfntly/table/bitmap/index_sub_table_format4.cc \
+	cpp/src/sfntly/table/bitmap/index_sub_table_format5.cc \
+	cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.cc \
+	cpp/src/sfntly/table/bitmap/small_glyph_metrics.cc \
+	cpp/src/sfntly/table/byte_array_table_builder.cc \
+	cpp/src/sfntly/table/core/cmap_table.cc \
+	cpp/src/sfntly/table/core/font_header_table.cc \
+	cpp/src/sfntly/table/core/horizontal_device_metrics_table.cc \
+	cpp/src/sfntly/table/core/horizontal_header_table.cc \
+	cpp/src/sfntly/table/core/horizontal_metrics_table.cc \
+	cpp/src/sfntly/table/core/maximum_profile_table.cc \
+	cpp/src/sfntly/table/core/name_table.cc \
+	cpp/src/sfntly/table/core/os2_table.cc \
+	cpp/src/sfntly/table/font_data_table.cc \
+	cpp/src/sfntly/table/generic_table_builder.cc \
+	cpp/src/sfntly/table/header.cc \
+	cpp/src/sfntly/table/subtable.cc \
+	cpp/src/sfntly/table/table.cc \
+	cpp/src/sfntly/table/table_based_table_builder.cc \
+	cpp/src/sfntly/table/truetype/glyph_table.cc \
+	cpp/src/sfntly/table/truetype/loca_table.cc \
+	cpp/src/sfntly/tag.cc \
+	cpp/src/sample/chromium/font_subsetter.cc \
+	cpp/src/sample/chromium/subsetter_impl.cc
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Debug := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Os \
+	-g \
+	-fomit-frame-pointer \
+	-fdata-sections \
+	-ffunction-sections
+
+MY_DEFS_Debug := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DSFNTLY_NO_EXCEPTION' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=1' \
+	'-DWTF_USE_DYNAMIC_ANNOTATIONS=1' \
+	'-D_DEBUG'
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Debug := \
+	$(LOCAL_PATH)/cpp/src \
+	$(LOCAL_PATH) \
+	external/icu4c/common \
+	external/icu4c/i18n \
+	frameworks/wilhelm/include \
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Debug := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+
+# Flags passed to both C and C++ files.
+MY_CFLAGS_Release := \
+	-fstack-protector \
+	--param=ssp-buffer-size=4 \
+	-Werror \
+	-fno-exceptions \
+	-fno-strict-aliasing \
+	-Wall \
+	-Wno-unused-parameter \
+	-Wno-missing-field-initializers \
+	-fvisibility=hidden \
+	-pipe \
+	-fPIC \
+	-fno-tree-sra \
+	-fuse-ld=gold \
+	-Wno-psabi \
+	-ffunction-sections \
+	-funwind-tables \
+	-g \
+	-fstack-protector \
+	-fno-short-enums \
+	-finline-limit=64 \
+	-Wa,--noexecstack \
+	-U_FORTIFY_SOURCE \
+	-Wno-extra \
+	-Wno-ignored-qualifiers \
+	-Wno-type-limits \
+	-Os \
+	-fno-ident \
+	-fdata-sections \
+	-ffunction-sections \
+	-fomit-frame-pointer
+
+MY_DEFS_Release := \
+	'-DANGLE_DX11' \
+	'-D_FILE_OFFSET_BITS=64' \
+	'-DNO_TCMALLOC' \
+	'-DDISCARDABLE_MEMORY_ALWAYS_SUPPORTED_NATIVELY' \
+	'-DSYSTEM_NATIVELY_SIGNALS_MEMORY_PRESSURE' \
+	'-DDISABLE_NACL' \
+	'-DCHROMIUM_BUILD' \
+	'-DUSE_LIBJPEG_TURBO=1' \
+	'-DUSE_PROPRIETARY_CODECS' \
+	'-DENABLE_CONFIGURATION_POLICY' \
+	'-DENABLE_GPU=1' \
+	'-DUSE_OPENSSL=1' \
+	'-DENABLE_EGLIMAGE=1' \
+	'-DSFNTLY_NO_EXCEPTION' \
+	'-DU_USING_ICU_NAMESPACE=0' \
+	'-D__STDC_CONSTANT_MACROS' \
+	'-D__STDC_FORMAT_MACROS' \
+	'-DANDROID' \
+	'-D__GNU_SOURCE=1' \
+	'-DUSE_STLPORT=1' \
+	'-D_STLP_USE_PTR_SPECIALIZATIONS=1' \
+	'-DCHROME_BUILD_ID=""' \
+	'-DNDEBUG' \
+	'-DNVALGRIND' \
+	'-DDYNAMIC_ANNOTATIONS_ENABLED=0' \
+	'-D_FORTIFY_SOURCE=2'
+
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES_Release := \
+	$(LOCAL_PATH)/cpp/src \
+	$(LOCAL_PATH) \
+	external/icu4c/common \
+	external/icu4c/i18n \
+	frameworks/wilhelm/include \
+
+
+# Flags passed to only C++ (and not C) files.
+LOCAL_CPPFLAGS_Release := \
+	-fno-rtti \
+	-fno-threadsafe-statics \
+	-fvisibility-inlines-hidden \
+	-Wsign-compare \
+	-Wno-abi \
+	-Wno-error=c++0x-compat \
+	-Wno-non-virtual-dtor \
+	-Wno-sign-promo
+
+LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
+LOCAL_C_INCLUDES := $(LOCAL_C_INCLUDES_$(GYP_CONFIGURATION))
+LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
+### Rules for final target.
+
+LOCAL_LDFLAGS_Debug := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,--gc-sections \
+	-Wl,-O1 \
+	-Wl,--as-needed
+
+
+LOCAL_LDFLAGS_Release := \
+	-Wl,-z,now \
+	-Wl,-z,relro \
+	-Wl,-z,noexecstack \
+	-fPIC \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-fuse-ld=gold \
+	-nostdlib \
+	-Wl,--no-undefined \
+	-Wl,--exclude-libs=ALL \
+	-Wl,--icf=safe \
+	-Wl,-O1 \
+	-Wl,--as-needed \
+	-Wl,--gc-sections
+
+
+LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
+
+LOCAL_STATIC_LIBRARIES :=
+
+# Enable grouping to fix circular references
+LOCAL_GROUP_STATIC_LIBRARIES := true
+
+LOCAL_SHARED_LIBRARIES := \
+	libstlport \
+	libdl \
+
+include external/stlport/libstlport.mk
+
+include $(BUILD_STATIC_LIBRARY)
\ No newline at end of file
diff --git a/COPYING.android b/COPYING.android
new file mode 100644
index 0000000..13bcce2
--- /dev/null
+++ b/COPYING.android
@@ -0,0 +1,2 @@
+See cpp/COPYING for license details.
+
diff --git a/CleanSpec.mk b/CleanSpec.mk
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/CleanSpec.mk
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/README.android b/README.android
new file mode 100644
index 0000000..e99dcf1
--- /dev/null
+++ b/README.android
@@ -0,0 +1,2 @@
+Current version:
+svn checkout http://sfntly.googlecode.com/svn/trunk/cpp/src@134 cpp/src
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
new file mode 100644
index 0000000..85932bc
--- /dev/null
+++ b/cpp/CMakeLists.txt
@@ -0,0 +1,123 @@
+########################################################################
+# CMake build script for Google Typography sfntly.
+cmake_minimum_required(VERSION 2.6.2)
+set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "good configs" FORCE)
+set(CMAKE_LEGACY_CYGWIN_WIN32 0)
+
+project(sfntly)
+
+# For gcc, make the default be debug build and valgrind friendly.
+if(CMAKE_COMPILER_IS_GNUCXX)
+  if(NOT CMAKE_BUILD_TYPE)
+    set(CMAKE_BUILD_TYPE Debug)
+    add_definitions("-DDEBUG -D_DEBUG -g -fno-inline -fno-omit-frame-pointer -fno-builtin")
+  endif(NOT CMAKE_BUILD_TYPE)
+endif(CMAKE_COMPILER_IS_GNUCXX)
+
+  set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib)
+  set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin)
+  include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src ext/gtest/include ext/gtest
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/sample ${CMAKE_CURRENT_SOURCE_DIR}/src/sample/subtly)
+
+# The following simulates Chrome compilation flags
+  add_definitions(-DSFNTLY_NO_EXCEPTION)
+if(CMAKE_COMPILER_IS_GNUCXX)
+  add_definitions(-D__wur=__attribute__\(\(warn_unused_result\)\) -Wall -Werror -fno-exceptions)
+endif(CMAKE_COMPILER_IS_GNUCXX)
+
+# Use STL for TinyXML library
+  add_definitions(-DTIXML_USE_STL)
+
+# Enable CMap and Bitmap handling
+  add_definitions(-DSFNTLY_EXPERIMENTAL)
+
+# VC specific flags
+if(MSVC10 OR MSVC90)
+  set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi /nologo /W4 /WX /O2 /Ob2 /Oy /GF /Gm- /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /GR-")
+  set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Zi /nologo /W4 /WX /Od /Oy- /RTC1 /MTd /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /GR-")
+  add_definitions(-D_UNICODE -DUNICODE)
+  include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ext/icu/include)
+  link_directories(${CMAKE_CURRENT_SOURCE_DIR}/ext/icu/lib)
+endif(MSVC10 OR MSVC90)
+
+  file(GLOB SFNTLY_CORE_FILES src/sfntly/*.h src/sfntly/*.cc)
+  file(GLOB SFNTLY_PORT_FILES src/sfntly/port/*.h src/sfntly/port/*.cc)
+  file(GLOB SFNTLY_DATA_FILES src/sfntly/data/*.h src/sfntly/data/*.cc)
+  file(GLOB SFNTLY_MATH_FILES src/sfntly/math/*.h src/sfntly/math/*.cc)
+  file(GLOB SFNTLY_TABLE_COMMON_FILES src/sfntly/table/*.h src/sfntly/table/*.cc)
+  file(GLOB SFNTLY_TABLE_BITMAP_FILES src/sfntly/table/bitmap/*.h src/sfntly/table/bitmap/*.cc)
+  file(GLOB SFNTLY_TABLE_CORE_FILES src/sfntly/table/core/*.h src/sfntly/table/core/*.cc)
+  file(GLOB SFNTLY_TABLE_TTF_FILES src/sfntly/table/truetype/*.h src/sfntly/table/truetype/*.cc)
+  source_group(core FILES ${SFNTLY_CORE_FILES})
+  source_group(ports FILES ${SFNTLY_PORT_FILES})
+  source_group(data FILES ${SFNTLY_DATA_FILES})
+  source_group(math FILES ${SFNTLY_MATH_FILES})
+  source_group(table FILES ${SFNTLY_TABLE_COMMON_FILES})
+  source_group(table\\bitmap FILES ${SFNTLY_TABLE_BITMAP_FILES})
+  source_group(table\\core FILES ${SFNTLY_TABLE_CORE_FILES})
+  source_group(table\\truetype FILES ${SFNTLY_TABLE_TTF_FILES})
+  add_library(sfntly
+              ${SFNTLY_CORE_FILES}
+              ${SFNTLY_PORT_FILES}
+              ${SFNTLY_DATA_FILES}
+              ${SFNTLY_MATH_FILES}
+              ${SFNTLY_TABLE_COMMON_FILES}
+              ${SFNTLY_TABLE_BITMAP_FILES}
+              ${SFNTLY_TABLE_CORE_FILES}
+              ${SFNTLY_TABLE_TTF_FILES})
+  file(GLOB_RECURSE SIMPLE_SUBSETTER src/sample/subsetter/*.h src/sample/subsetter/*.cc
+                                     src/sfntly/tools/*.h src/sfntly/tools/*.cc)
+  add_executable(subsetter ${SIMPLE_SUBSETTER})
+  target_link_libraries(subsetter sfntly icuuc)
+if(CMAKE_COMPILER_IS_GNUCXX)
+  target_link_libraries(subsetter pthread)
+endif(CMAKE_COMPILER_IS_GNUCXX)
+  file(GLOB TINYXML src/test/tinyxml/*.cpp)
+  add_library(tinyxml
+              ${TINYXML})
+  file(GLOB TEST_CASES src/test/*.cc src/test/autogenerated/*.cc)
+  file(GLOB CHROME_SUBSETTER_LIB
+    src/sample/chromium/subsetter_impl.h
+    src/sample/chromium/subsetter_impl.cc
+    src/sample/chromium/font_subsetter.cc
+    src/sample/chromium/font_subsetter.h)
+  add_executable(unit_test
+    ${TEST_CASES} ${CHROME_SUBSETTER_LIB}
+    ext/gtest/src/gtest-all.cc
+    ext/gtest/src/gtest_main.cc)
+  target_link_libraries(unit_test sfntly icuuc tinyxml)
+if(CMAKE_COMPILER_IS_GNUCXX)
+  target_link_libraries(unit_test pthread)
+endif(CMAKE_COMPILER_IS_GNUCXX)
+  # subtly targets
+  file(GLOB SUBTLY_FILES src/sample/subtly/*.h src/sample/subtly/*.cc)
+  file(GLOB SUBTLY_MAINS src/sample/subtly/*main.cc)
+  list(REMOVE_ITEM SUBTLY_FILES ${SUBTLY_MAINS})
+  add_library(subtly
+    ${SUBTLY_FILES})
+  add_executable(subtly_subsetter
+    src/sample/subtly/subsetter_main.cc)
+  target_link_libraries(subtly_subsetter subtly sfntly icuuc)
+if(CMAKE_COMPILER_IS_GNUCXX)
+  target_link_libraries(subtly_subsetter pthread)
+endif(CMAKE_COMPILER_IS_GNUCXX)
+  add_executable(subtly_merger
+    src/sample/subtly/merger_main.cc)
+  target_link_libraries(subtly_merger subtly sfntly icuuc)
+if(CMAKE_COMPILER_IS_GNUCXX)
+  target_link_libraries(subtly_merger pthread)
+endif(CMAKE_COMPILER_IS_GNUCXX)
+  add_executable(subtly_debug
+    src/sample/subtly/debug_main.cc)
+  target_link_libraries(subtly_debug subtly sfntly icuuc)
+if(CMAKE_COMPILER_IS_GNUCXX)
+  target_link_libraries(subtly_debug pthread)
+endif(CMAKE_COMPILER_IS_GNUCXX)
+   add_executable(chrome_subsetter
+     ${CHROME_SUBSETTER_LIB}
+     src/sample/chromium/chrome_subsetter.cc
+   )
+   target_link_libraries(chrome_subsetter sfntly icuuc)
+ if(CMAKE_COMPILER_IS_GNUCXX)
+   target_link_libraries(chrome_subsetter pthread)
+ endif(CMAKE_COMPILER_IS_GNUCXX)
diff --git a/cpp/COPYING.txt b/cpp/COPYING.txt
new file mode 100644
index 0000000..c61423c
--- /dev/null
+++ b/cpp/COPYING.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2011 Google Inc. All Rights Reserved.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
diff --git a/cpp/README.txt b/cpp/README.txt
new file mode 100644
index 0000000..ac2b43a
--- /dev/null
+++ b/cpp/README.txt
@@ -0,0 +1,3 @@
+Please refer to http://code.google.com/p/sfntly/wiki/build_cpp regarding how to build sfntly.
+
+sfntly wiki contains other useful documents: http://code.google.com/p/sfntly/w/list
\ No newline at end of file
diff --git a/cpp/src/sample/chromium/chrome_subsetter.cc b/cpp/src/sample/chromium/chrome_subsetter.cc
new file mode 100644
index 0000000..df15c18
--- /dev/null
+++ b/cpp/src/sample/chromium/chrome_subsetter.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include <vector>
+#include <string>
+#include <sstream>
+
+#include "sfntly/port/type.h"
+#include "font_subsetter.h"
+
+template <typename T>
+class HexTo {
+ public:
+  explicit HexTo(const char* in) {
+    std::stringstream ss;
+    ss << std::hex << in;
+    ss >> value_;
+  }
+  operator T() const { return value_; }
+
+ private:
+  T value_;
+};
+
+bool LoadFile(const char* input_file_path, sfntly::ByteVector* input_buffer) {
+  assert(input_file_path);
+  assert(input_buffer);
+
+  FILE* input_file = NULL;
+#if defined WIN32
+  fopen_s(&input_file, input_file_path, "rb");
+#else
+  input_file = fopen(input_file_path, "rb");
+#endif
+  if (input_file == NULL) {
+    return false;
+  }
+  fseek(input_file, 0, SEEK_END);
+  size_t file_size = ftell(input_file);
+  fseek(input_file, 0, SEEK_SET);
+  input_buffer->resize(file_size);
+  size_t bytes_read = fread(&((*input_buffer)[0]), 1, file_size, input_file);
+  fclose(input_file);
+  return bytes_read == file_size;
+}
+
+bool SaveFile(const char* output_file_path, const unsigned char* output_buffer,
+              int buffer_length) {
+  int byte_count = 0;
+  if (buffer_length > 0) {
+    FILE* output_file = NULL;
+#if defined WIN32
+    fopen_s(&output_file, output_file_path, "wb");
+#else
+    output_file = fopen(output_file_path, "wb");
+#endif
+    if (output_file) {
+      byte_count = fwrite(output_buffer, 1, buffer_length, output_file);
+      fflush(output_file);
+      fclose(output_file);
+    }
+    return buffer_length == byte_count;
+  }
+  return false;
+}
+
+bool StringToGlyphId(const char* input, std::vector<unsigned int>* glyph_ids) {
+  assert(input);
+  std::string hex_csv = input;
+  size_t start = 0;
+  size_t end = hex_csv.find_first_of(",");
+  while (end != std::string::npos) {
+    glyph_ids->push_back(
+        HexTo<unsigned int>(hex_csv.substr(start, end - start).c_str()));
+    start = end + 1;
+    end = hex_csv.find_first_of(",", start);
+  }
+  glyph_ids->push_back(HexTo<unsigned int>(hex_csv.substr(start).c_str()));
+  return glyph_ids->size() > 0;
+}
+
+int main(int argc, char** argv) {
+  if (argc < 5) {
+    fprintf(stderr,
+        "Usage: %s <input path> <output path> <font name> <glyph ids>\n",
+        argv[0]);
+    fprintf(stderr, "\tGlyph ids are comma separated hex values\n");
+    fprintf(stderr, "\te.g. 20,1a,3b,4f\n");
+    return 0;
+  }
+
+  sfntly::ByteVector input_buffer;
+  if (!LoadFile(argv[1], &input_buffer)) {
+    fprintf(stderr, "ERROR: unable to load font file %s\n", argv[1]);
+    return 0;
+  }
+
+  std::vector<unsigned int> glyph_ids;
+  if (!StringToGlyphId(argv[4], &glyph_ids)) {
+    fprintf(stderr, "ERROR: unable to parse input glyph id\n");
+    return 0;
+  }
+
+  unsigned char* output_buffer = NULL;
+  int output_length =
+      SfntlyWrapper::SubsetFont(argv[3],
+                                &(input_buffer[0]),
+                                input_buffer.size(),
+                                &(glyph_ids[0]),
+                                glyph_ids.size(),
+                                &output_buffer);
+
+  int result = SaveFile(argv[2], output_buffer, output_length) ? 1 : 0;
+  delete[] output_buffer;
+  return result;
+}
diff --git a/cpp/src/sample/chromium/font_subsetter.cc b/cpp/src/sample/chromium/font_subsetter.cc
new file mode 100644
index 0000000..14f5494
--- /dev/null
+++ b/cpp/src/sample/chromium/font_subsetter.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "font_subsetter.h"
+
+#include "subsetter_impl.h"
+
+int SfntlyWrapper::SubsetFont(const char* font_name,
+                              const unsigned char* original_font,
+                              size_t font_size,
+                              const unsigned int* glyph_ids,
+                              size_t glyph_count,
+                              unsigned char** output_buffer) {
+  if (output_buffer == NULL ||
+      original_font == NULL || font_size == 0 ||
+      glyph_ids == NULL || glyph_count == 0) {
+    return 0;
+  }
+
+  sfntly::SubsetterImpl subsetter;
+  if (!subsetter.LoadFont(font_name, original_font, font_size)) {
+    return -1;  // Load error or font not found.
+  }
+
+  return subsetter.SubsetFont(glyph_ids, glyph_count, output_buffer);
+}
diff --git a/cpp/src/sample/chromium/font_subsetter.h b/cpp/src/sample/chromium/font_subsetter.h
new file mode 100644
index 0000000..07b1b5b
--- /dev/null
+++ b/cpp/src/sample/chromium/font_subsetter.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// File is originally from Chromium third_party/sfntly/src/subsetter.
+// Use as test case in sfntly so that problems can be caught in upstream early.
+#ifndef SFNTLY_CPP_SRC_TEST_FONT_SUBSETTER_H_
+#define SFNTLY_CPP_SRC_TEST_FONT_SUBSETTER_H_
+
+#include <cstddef>
+
+class SfntlyWrapper {
+ public:
+
+  // Font subsetting API
+  //
+  // Input TTF/TTC/OTF fonts, specify the glyph IDs to subset, and the subset
+  // font is returned in |output_buffer| (caller to delete[]).  Return value is
+  // the length of output_buffer allocated.
+  //
+  // If subsetting fails, a negative value is returned.  If none of the glyph
+  // IDs specified is found, the function will return 0.
+  //
+  // |font_name|      Font name, required for TTC files.  If specified NULL,
+  //                  the first available font is selected.
+  // |original_font|  Original font file contents.
+  // |font_size|      Size of |original_font| in bytes.
+  // |glyph_ids|      Glyph IDs to subset.  If the specified glyph ID is not
+  //                  found in the font file, it will be ignored silently.
+  // |glyph_count|    Number of glyph IDs in |glyph_ids|
+  // |output_buffer|  Generated subset font.  Caller to delete[].
+  static int SubsetFont(const char* font_name,
+                        const unsigned char* original_font,
+                        size_t font_size,
+                        const unsigned int* glyph_ids,
+                        size_t glyph_count,
+                        unsigned char** output_buffer);
+};
+
+#endif  // SFNTLY_CPP_SRC_TEST_FONT_SUBSETTER_H_
diff --git a/cpp/src/sample/chromium/subsetter_impl.cc b/cpp/src/sample/chromium/subsetter_impl.cc
new file mode 100644
index 0000000..528e336
--- /dev/null
+++ b/cpp/src/sample/chromium/subsetter_impl.cc
@@ -0,0 +1,785 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "subsetter_impl.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <iterator>
+#include <map>
+#include <set>
+
+#include "sfntly/table/bitmap/eblc_table.h"
+#include "sfntly/table/bitmap/ebdt_table.h"
+#include "sfntly/table/bitmap/index_sub_table.h"
+#include "sfntly/table/bitmap/index_sub_table_format1.h"
+#include "sfntly/table/bitmap/index_sub_table_format2.h"
+#include "sfntly/table/bitmap/index_sub_table_format3.h"
+#include "sfntly/table/bitmap/index_sub_table_format4.h"
+#include "sfntly/table/bitmap/index_sub_table_format5.h"
+#include "sfntly/table/core/name_table.h"
+#include "sfntly/tag.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/port/memory_input_stream.h"
+#include "sfntly/port/memory_output_stream.h"
+
+#if defined U_USING_ICU_NAMESPACE
+  U_NAMESPACE_USE
+#endif
+
+namespace {
+
+using namespace sfntly;
+
+// The bitmap tables must be greater than 16KB to trigger bitmap subsetter.
+static const int BITMAP_SIZE_THRESHOLD = 16384;
+
+void ConstructName(UChar* name_part, UnicodeString* name, int32_t name_id) {
+  switch (name_id) {
+    case NameId::kFullFontName:
+      *name = name_part;
+      break;
+    case NameId::kFontFamilyName:
+    case NameId::kPreferredFamily:
+    case NameId::kWWSFamilyName: {
+      UnicodeString original = *name;
+      *name = name_part;
+      *name += original;
+      break;
+    }
+    case NameId::kFontSubfamilyName:
+    case NameId::kPreferredSubfamily:
+    case NameId::kWWSSubfamilyName:
+      *name += name_part;
+      break;
+    default:
+      // This name part is not used to construct font name (e.g. copyright).
+      // Simply ignore it.
+      break;
+  }
+}
+
+int32_t HashCode(int32_t platform_id, int32_t encoding_id, int32_t language_id,
+                 int32_t name_id) {
+  int32_t result = platform_id << 24 | encoding_id << 16 | language_id << 8;
+  if (name_id == NameId::kFullFontName) {
+    result |= 0xff;
+  } else if (name_id == NameId::kPreferredFamily ||
+             name_id == NameId::kPreferredSubfamily) {
+    result |= 0xf;
+  } else if (name_id == NameId::kWWSFamilyName ||
+             name_id == NameId::kWWSSubfamilyName) {
+    result |= 1;
+  }
+  return result;
+}
+
+bool HasName(const char* font_name, Font* font) {
+  UnicodeString font_string = UnicodeString::fromUTF8(font_name);
+  if (font_string.isEmpty())
+    return false;
+  UnicodeString regular_suffix = UnicodeString::fromUTF8(" Regular");
+  UnicodeString alt_font_string = font_string;
+  alt_font_string += regular_suffix;
+
+  typedef std::map<int32_t, UnicodeString> NameMap;
+  NameMap names;
+  NameTablePtr name_table = down_cast<NameTable*>(font->GetTable(Tag::name));
+  if (name_table == NULL) {
+    return false;
+  }
+
+  for (int32_t i = 0; i < name_table->NameCount(); ++i) {
+    switch (name_table->NameId(i)) {
+      case NameId::kFontFamilyName:
+      case NameId::kFontSubfamilyName:
+      case NameId::kFullFontName:
+      case NameId::kPreferredFamily:
+      case NameId::kPreferredSubfamily:
+      case NameId::kWWSFamilyName:
+      case NameId::kWWSSubfamilyName: {
+        UChar* name_part = name_table->Name(i);
+        if (name_part == NULL) {
+          continue;
+        }
+        int32_t hash_code = HashCode(name_table->PlatformId(i),
+                                     name_table->EncodingId(i),
+                                     name_table->LanguageId(i),
+                                     name_table->NameId(i));
+        ConstructName(name_part, &(names[hash_code]), name_table->NameId(i));
+        delete[] name_part;
+        break;
+      }
+      default:
+        break;
+    }
+  }
+
+  if (!names.empty()) {
+    for (NameMap::iterator i = names.begin(), e = names.end(); i != e; ++i) {
+      if (i->second.caseCompare(font_string, 0) == 0 ||
+          i->second.caseCompare(alt_font_string, 0) == 0) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+Font* FindFont(const char* font_name, const FontArray& font_array) {
+  if (font_array.empty() || font_array[0] == NULL) {
+    return NULL;
+  }
+
+  if (font_name && strlen(font_name)) {
+    for (FontArray::const_iterator i = font_array.begin(), e = font_array.end();
+         i != e; ++i) {
+      if (HasName(font_name, i->p_)) {
+        return i->p_;
+      }
+    }
+  }
+
+  return font_array[0].p_;
+}
+
+bool ResolveCompositeGlyphs(GlyphTable* glyph_table,
+                            LocaTable* loca_table,
+                            const unsigned int* glyph_ids,
+                            size_t glyph_count,
+                            IntegerSet* glyph_id_processed) {
+  if (glyph_table == NULL || loca_table == NULL ||
+      glyph_ids == NULL || glyph_count == 0 || glyph_id_processed == NULL) {
+    return false;
+  }
+
+  // Sort and uniquify glyph ids.
+  IntegerSet glyph_id_remaining;
+  glyph_id_remaining.insert(0);  // Always include glyph id 0.
+  for (size_t i = 0; i < glyph_count; ++i) {
+    glyph_id_remaining.insert(glyph_ids[i]);
+  }
+
+  // Identify if any given glyph id maps to a composite glyph.  If so, include
+  // the glyphs referenced by that composite glyph.
+  while (!glyph_id_remaining.empty()) {
+    IntegerSet comp_glyph_id;
+    for (IntegerSet::iterator i = glyph_id_remaining.begin(),
+                              e = glyph_id_remaining.end(); i != e; ++i) {
+      if (*i < 0 || *i >= loca_table->num_glyphs()) {
+        // Invalid glyph id, ignore.
+        continue;
+      }
+
+      int32_t length = loca_table->GlyphLength(*i);
+      if (length == 0) {
+        // Empty glyph, ignore.
+        continue;
+      }
+      int32_t offset = loca_table->GlyphOffset(*i);
+
+      GlyphPtr glyph;
+      glyph.Attach(glyph_table->GetGlyph(offset, length));
+      if (glyph == NULL) {
+        // Error finding glyph, ignore.
+        continue;
+      }
+
+      if (glyph->GlyphType() == GlyphType::kComposite) {
+        Ptr<GlyphTable::CompositeGlyph> comp_glyph =
+            down_cast<GlyphTable::CompositeGlyph*>(glyph.p_);
+        for (int32_t j = 0; j < comp_glyph->NumGlyphs(); ++j) {
+          int32_t glyph_id = comp_glyph->GlyphIndex(j);
+          if (glyph_id_processed->find(glyph_id) == glyph_id_processed->end() &&
+              glyph_id_remaining.find(glyph_id) == glyph_id_remaining.end()) {
+            comp_glyph_id.insert(comp_glyph->GlyphIndex(j));
+          }
+        }
+      }
+
+      glyph_id_processed->insert(*i);
+    }
+
+    glyph_id_remaining.clear();
+    glyph_id_remaining = comp_glyph_id;
+  }
+
+  return true;
+}
+
+bool SetupGlyfBuilders(Font::Builder* font_builder,
+                       GlyphTable* glyph_table,
+                       LocaTable* loca_table,
+                       const IntegerSet& glyph_ids) {
+  if (!font_builder || !glyph_table || !loca_table) {
+    return false;
+  }
+
+  GlyphTableBuilderPtr glyph_table_builder =
+      down_cast<GlyphTable::Builder*>(font_builder->NewTableBuilder(Tag::glyf));
+  LocaTableBuilderPtr loca_table_builder =
+      down_cast<LocaTable::Builder*>(font_builder->NewTableBuilder(Tag::loca));
+  if (glyph_table_builder == NULL || loca_table_builder == NULL) {
+    // Out of memory.
+    return false;
+  }
+
+  // Extract glyphs and setup loca list.
+  IntegerList loca_list;
+  loca_list.resize(loca_table->num_glyphs());
+  loca_list.push_back(0);
+  int32_t last_glyph_id = 0;
+  int32_t last_offset = 0;
+  GlyphTable::GlyphBuilderList* glyph_builders =
+      glyph_table_builder->GlyphBuilders();
+  for (IntegerSet::const_iterator i = glyph_ids.begin(), e = glyph_ids.end();
+                                  i != e; ++i) {
+    int32_t length = loca_table->GlyphLength(*i);
+    int32_t offset = loca_table->GlyphOffset(*i);
+
+    GlyphPtr glyph;
+    glyph.Attach(glyph_table->GetGlyph(offset, length));
+
+    // Add glyph to new glyf table.
+    ReadableFontDataPtr data = glyph->ReadFontData();
+    WritableFontDataPtr copy_data;
+    copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length()));
+    data->CopyTo(copy_data);
+    GlyphBuilderPtr glyph_builder;
+    glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data));
+    glyph_builders->push_back(glyph_builder);
+
+    // Configure loca list.
+    for (int32_t j = last_glyph_id + 1; j <= *i; ++j) {
+      loca_list[j] = last_offset;
+    }
+    last_offset += length;
+    loca_list[*i + 1] = last_offset;
+    last_glyph_id = *i;
+  }
+  for (int32_t j = last_glyph_id + 1; j <= loca_table->num_glyphs(); ++j) {
+    loca_list[j] = last_offset;
+  }
+  loca_table_builder->SetLocaList(&loca_list);
+
+  return true;
+}
+
+bool HasOverlap(int32_t range_begin, int32_t range_end,
+                const IntegerSet& glyph_ids) {
+  if (range_begin == range_end) {
+    return glyph_ids.find(range_begin) != glyph_ids.end();
+  } else if (range_end > range_begin) {
+    IntegerSet::const_iterator left = glyph_ids.lower_bound(range_begin);
+    IntegerSet::const_iterator right = glyph_ids.lower_bound(range_end);
+    return right != left;
+  }
+  return false;
+}
+
+// Initialize builder, returns false if glyph_id subset is not covered.
+// Not thread-safe, caller to ensure object life-time.
+bool InitializeBitmapBuilder(EbdtTable::Builder* ebdt, EblcTable::Builder* eblc,
+                             const IntegerSet& glyph_ids) {
+  BitmapLocaList loca_list;
+  BitmapSizeTableBuilderList* strikes = eblc->BitmapSizeBuilders();
+
+  // Note: Do not call eblc_builder->GenerateLocaList(&loca_list) and then
+  //       ebdt_builder->SetLoca(loca_list).  For fonts like SimSun, there are
+  //       >28K glyphs inside, where a typical usage will be <1K glyphs.  Doing
+  //       the calls improperly will result in creation of >100K objects that
+  //       will be destroyed immediately, inducing significant slowness.
+  IntegerList removed_strikes;
+  for (size_t i = 0; i < strikes->size(); i++) {
+    if (!HasOverlap((*strikes)[i]->StartGlyphIndex(),
+                    (*strikes)[i]->EndGlyphIndex(), glyph_ids)) {
+      removed_strikes.push_back(i);
+      continue;
+    }
+
+    IndexSubTableBuilderList* index_builders =
+        (*strikes)[i]->IndexSubTableBuilders();
+    IntegerList removed_indexes;
+    BitmapGlyphInfoMap info_map;
+    for (size_t j = 0; j < index_builders->size(); ++j) {
+      if ((*index_builders)[j] == NULL) {
+        // Subtable is malformed, let's just skip it.
+        removed_indexes.push_back(j);
+        continue;
+      }
+      int32_t first_glyph_id = (*index_builders)[j]->first_glyph_index();
+      int32_t last_glyph_id = (*index_builders)[j]->last_glyph_index();
+      if (!HasOverlap(first_glyph_id, last_glyph_id, glyph_ids)) {
+        removed_indexes.push_back(j);
+        continue;
+      }
+      for (IntegerSet::const_iterator gid = glyph_ids.begin(),
+                                      gid_end = glyph_ids.end();
+                                      gid != gid_end; gid++) {
+        if (*gid < first_glyph_id) {
+          continue;
+        }
+        if (*gid > last_glyph_id) {
+          break;
+        }
+        BitmapGlyphInfoPtr info;
+        info.Attach((*index_builders)[j]->GlyphInfo(*gid));
+        if (info && info->length()) {  // Do not include gid without bitmap
+          info_map[*gid] = info;
+        }
+      }
+    }
+    if (!info_map.empty()) {
+      loca_list.push_back(info_map);
+    } else {
+      removed_strikes.push_back(i);  // Detected null entries.
+    }
+
+    // Remove unused index sub tables
+    for (IntegerList::reverse_iterator j = removed_indexes.rbegin(),
+                                       e = removed_indexes.rend();
+                                       j != e; j++) {
+      index_builders->erase(index_builders->begin() + *j);
+    }
+  }
+  if (removed_strikes.size() == strikes->size() || loca_list.empty()) {
+    return false;
+  }
+
+  for (IntegerList::reverse_iterator i = removed_strikes.rbegin(),
+                                     e = removed_strikes.rend(); i != e; i++) {
+    strikes->erase(strikes->begin() + *i);
+  }
+
+  if (strikes->empty()) {  // no glyph covered, can safely drop the builders.
+    return false;
+  }
+
+  ebdt->SetLoca(&loca_list);
+  ebdt->GlyphBuilders();  // Initialize the builder.
+  return true;
+}
+
+void CopyBigGlyphMetrics(BigGlyphMetrics::Builder* source,
+                         BigGlyphMetrics::Builder* target) {
+  target->SetHeight(static_cast<byte_t>(source->Height()));
+  target->SetWidth(static_cast<byte_t>(source->Width()));
+  target->SetHoriBearingX(static_cast<byte_t>(source->HoriBearingX()));
+  target->SetHoriBearingY(static_cast<byte_t>(source->HoriBearingY()));
+  target->SetHoriAdvance(static_cast<byte_t>(source->HoriAdvance()));
+  target->SetVertBearingX(static_cast<byte_t>(source->VertBearingX()));
+  target->SetVertBearingY(static_cast<byte_t>(source->VertBearingY()));
+  target->SetVertAdvance(static_cast<byte_t>(source->VertAdvance()));
+}
+
+CALLER_ATTACH IndexSubTable::Builder*
+ConstructIndexFormat4(IndexSubTable::Builder* b, const BitmapGlyphInfoMap& loca,
+                      int32_t* image_data_offset) {
+  IndexSubTableFormat4BuilderPtr builder4;
+  builder4.Attach(IndexSubTableFormat4::Builder::CreateBuilder());
+  CodeOffsetPairBuilderList offset_pairs;
+
+  size_t offset = 0;
+  int32_t lower_bound = b->first_glyph_index();
+  int32_t upper_bound = b->last_glyph_index();
+  int32_t last_gid = -1;
+  BitmapGlyphInfoMap::const_iterator i = loca.lower_bound(lower_bound);
+  BitmapGlyphInfoMap::const_iterator end = loca.end();
+  if (i != end) {
+    last_gid = i->first;
+    builder4->set_first_glyph_index(last_gid);
+    builder4->set_image_format(b->image_format());
+    builder4->set_image_data_offset(*image_data_offset);
+  }
+  for (; i != end; i++) {
+    int32_t gid = i->first;
+    if (gid > upper_bound) {
+      break;
+    }
+    offset_pairs.push_back(
+        IndexSubTableFormat4::CodeOffsetPairBuilder(gid, offset));
+    offset += i->second->length();
+    last_gid = gid;
+  }
+  offset_pairs.push_back(
+      IndexSubTableFormat4::CodeOffsetPairBuilder(-1, offset));
+  builder4->set_last_glyph_index(last_gid);
+  *image_data_offset += offset;
+  builder4->SetOffsetArray(offset_pairs);
+
+  return builder4.Detach();
+}
+
+CALLER_ATTACH IndexSubTable::Builder*
+ConstructIndexFormat5(IndexSubTable::Builder* b, const BitmapGlyphInfoMap& loca,
+                      int32_t* image_data_offset) {
+  IndexSubTableFormat5BuilderPtr new_builder;
+  new_builder.Attach(IndexSubTableFormat5::Builder::CreateBuilder());
+
+  // Copy BigMetrics
+  int32_t image_size = 0;
+  if (b->index_format() == IndexSubTable::Format::FORMAT_2) {
+    IndexSubTableFormat2BuilderPtr builder2 =
+      down_cast<IndexSubTableFormat2::Builder*>(b);
+    CopyBigGlyphMetrics(builder2->BigMetrics(), new_builder->BigMetrics());
+    image_size = builder2->ImageSize();
+  } else {
+    IndexSubTableFormat5BuilderPtr builder5 =
+      down_cast<IndexSubTableFormat5::Builder*>(b);
+    BigGlyphMetricsBuilderPtr metrics_builder;
+    CopyBigGlyphMetrics(builder5->BigMetrics(), new_builder->BigMetrics());
+    image_size = builder5->ImageSize();
+  }
+
+  IntegerList* glyph_array = new_builder->GlyphArray();
+  size_t offset = 0;
+  int32_t lower_bound = b->first_glyph_index();
+  int32_t upper_bound = b->last_glyph_index();
+  int32_t last_gid = -1;
+  BitmapGlyphInfoMap::const_iterator i = loca.lower_bound(lower_bound);
+  BitmapGlyphInfoMap::const_iterator end = loca.end();
+  if (i != end) {
+    last_gid = i->first;
+    new_builder->set_first_glyph_index(last_gid);
+    new_builder->set_image_format(b->image_format());
+    new_builder->set_image_data_offset(*image_data_offset);
+    new_builder->SetImageSize(image_size);
+  }
+  for (; i != end; i++) {
+    int32_t gid = i->first;
+    if (gid > upper_bound) {
+      break;
+    }
+    glyph_array->push_back(gid);
+    offset += i->second->length();
+    last_gid = gid;
+  }
+  new_builder->set_last_glyph_index(last_gid);
+  *image_data_offset += offset;
+  return new_builder.Detach();
+}
+
+CALLER_ATTACH IndexSubTable::Builder*
+SubsetIndexSubTable(IndexSubTable::Builder* builder,
+                    const BitmapGlyphInfoMap& loca,
+                    int32_t* image_data_offset) {
+  switch (builder->index_format()) {
+    case IndexSubTable::Format::FORMAT_1:
+    case IndexSubTable::Format::FORMAT_3:
+    case IndexSubTable::Format::FORMAT_4:
+      return ConstructIndexFormat4(builder, loca, image_data_offset);
+    case IndexSubTable::Format::FORMAT_2:
+    case IndexSubTable::Format::FORMAT_5:
+      return ConstructIndexFormat5(builder, loca, image_data_offset);
+    default:
+      assert(false);
+      break;
+  }
+  return NULL;
+}
+
+}
+
+namespace sfntly {
+
+// Not thread-safe, caller to ensure object life-time.
+void SubsetEBLC(EblcTable::Builder* eblc, const BitmapLocaList& new_loca) {
+  BitmapSizeTableBuilderList* size_builders = eblc->BitmapSizeBuilders();
+  if (size_builders == NULL) {
+    return;
+  }
+
+  int32_t image_data_offset = EbdtTable::Offset::kHeaderLength;
+  for (size_t strike = 0; strike < size_builders->size(); ++strike) {
+    IndexSubTableBuilderList* index_builders =
+        (*size_builders)[strike]->IndexSubTableBuilders();
+    for (size_t index = 0; index < index_builders->size(); ++index) {
+      IndexSubTable::Builder* new_builder_raw =
+          SubsetIndexSubTable((*index_builders)[index], new_loca[strike],
+                              &image_data_offset);
+      if (NULL != new_builder_raw) {
+        (*index_builders)[index].Attach(new_builder_raw);
+      }
+    }
+  }
+}
+
+// EBLC structure (from stuartg)
+//  header
+//  bitmapSizeTable[]
+//    one per strike
+//    holds strike metrics - sbitLineMetrics
+//    holds info about indexSubTableArray
+//  indexSubTableArray[][]
+//    one per strike and then one per indexSubTable for that strike
+//    holds info about the indexSubTable
+//    the indexSubTable entries pointed to can be of different formats
+//  indexSubTable
+//    one per indexSubTableArray entry
+//    tells how to get the glyphs
+//    may hold the glyph metrics if they are uniform for all the glyphs in range
+// Please note that the structure can also be
+//  {indexSubTableArray[], indexSubTables[]}[]
+//  This way is also legal and in fact how Microsoft fonts are laid out.
+//
+// There is nothing that says that the indexSubTableArray entries and/or the
+// indexSubTable items need to be unique. They may be shared between strikes.
+//
+// EBDT structure:
+//  header
+//  glyphs
+//    amorphous blob of data
+//    different glyphs that are only able to be figured out from the EBLC table
+//    may hold metrics - depends on the EBLC entry that pointed to them
+
+// Subsetting EBLC table (from arthurhsu)
+//  Most pages use only a fraction (hundreds or less) glyphs out of a given font
+//  (which can have >20K glyphs for CJK).  It's safe to assume that the subset
+//  font will have sparse bitmap glyphs.  So we reconstruct the EBLC table as
+//  format 4 or 5 here.
+
+enum BuildersToRemove {
+  kRemoveNone,
+  kRemoveBDAT,
+  kRemoveBDATAndEBDT,
+  kRemoveEBDT
+};
+
+int SetupBitmapBuilders(Font* font, Font::Builder* font_builder,
+                        const IntegerSet& glyph_ids) {
+  if (!font || !font_builder) {
+    return false;
+  }
+
+  // Check if bitmap table exists.
+  EbdtTablePtr ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::EBDT));
+  EblcTablePtr eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::EBLC));
+  bool use_ebdt = (ebdt_table != NULL && eblc_table != NULL);
+  if (!use_ebdt) {
+    ebdt_table = down_cast<EbdtTable*>(font->GetTable(Tag::bdat));
+    eblc_table = down_cast<EblcTable*>(font->GetTable(Tag::bloc));
+    if (ebdt_table == NULL || eblc_table == NULL) {
+      return kRemoveNone;
+    }
+  }
+
+  // If the bitmap table's size is too small, skip subsetting.
+  if (ebdt_table->DataLength() + eblc_table->DataLength() <
+      BITMAP_SIZE_THRESHOLD) {
+    return use_ebdt ? kRemoveBDAT : kRemoveNone;
+  }
+
+  // Get the builders.
+  EbdtTableBuilderPtr ebdt_table_builder = down_cast<EbdtTable::Builder*>(
+      font_builder->NewTableBuilder(use_ebdt ? Tag::EBDT : Tag::bdat,
+                                    ebdt_table->ReadFontData()));
+  EblcTableBuilderPtr eblc_table_builder = down_cast<EblcTable::Builder*>(
+      font_builder->NewTableBuilder(use_ebdt ? Tag::EBLC : Tag::bloc,
+                                    eblc_table->ReadFontData()));
+  if (ebdt_table_builder == NULL || eblc_table_builder == NULL) {
+    // Out of memory.
+    return use_ebdt ? kRemoveBDAT : kRemoveNone;
+  }
+
+  if (!InitializeBitmapBuilder(ebdt_table_builder, eblc_table_builder,
+                               glyph_ids)) {
+    // Bitmap tables do not cover the glyphs in our subset.
+    font_builder->RemoveTableBuilder(use_ebdt ? Tag::EBLC : Tag::bloc);
+    font_builder->RemoveTableBuilder(use_ebdt ? Tag::EBDT : Tag::bdat);
+    return use_ebdt ? kRemoveBDATAndEBDT : kRemoveEBDT;
+  }
+
+  BitmapLocaList new_loca;
+  ebdt_table_builder->GenerateLocaList(&new_loca);
+  SubsetEBLC(eblc_table_builder, new_loca);
+
+  return use_ebdt ? kRemoveBDAT : kRemoveNone;
+}
+
+SubsetterImpl::SubsetterImpl() {
+}
+
+SubsetterImpl::~SubsetterImpl() {
+}
+
+bool SubsetterImpl::LoadFont(const char* font_name,
+                             const unsigned char* original_font,
+                             size_t font_size) {
+  MemoryInputStream mis;
+  mis.Attach(original_font, font_size);
+  if (factory_ == NULL) {
+    factory_.Attach(FontFactory::GetInstance());
+  }
+
+  FontArray font_array;
+  factory_->LoadFonts(&mis, &font_array);
+  font_ = FindFont(font_name, font_array);
+  if (font_ == NULL) {
+    return false;
+  }
+
+  return true;
+}
+
+int SubsetterImpl::SubsetFont(const unsigned int* glyph_ids,
+                              size_t glyph_count,
+                              unsigned char** output_buffer) {
+  if (factory_ == NULL || font_ == NULL) {
+    return -1;
+  }
+
+  // Find glyf and loca table.
+  GlyphTablePtr glyph_table =
+      down_cast<GlyphTable*>(font_->GetTable(Tag::glyf));
+  LocaTablePtr loca_table = down_cast<LocaTable*>(font_->GetTable(Tag::loca));
+  if (glyph_table == NULL || loca_table == NULL) {
+    // We are not able to subset the font.
+    return 0;
+  }
+
+  IntegerSet glyph_id_processed;
+  if (!ResolveCompositeGlyphs(glyph_table, loca_table,
+                              glyph_ids, glyph_count, &glyph_id_processed) ||
+      glyph_id_processed.empty()) {
+    return 0;
+  }
+
+  FontPtr new_font;
+  new_font.Attach(Subset(glyph_id_processed, glyph_table, loca_table));
+  if (new_font == NULL) {
+    return 0;
+  }
+
+  MemoryOutputStream output_stream;
+  factory_->SerializeFont(new_font, &output_stream);
+  int length = static_cast<int>(output_stream.Size());
+  if (length > 0) {
+    *output_buffer = new unsigned char[length];
+    memcpy(*output_buffer, output_stream.Get(), length);
+  }
+
+  return length;
+}
+
+// Long comments regarding TTF tables and PDF (from stuartg)
+//
+// According to PDF spec 1.4 (section 5.8), the following tables must be
+// present:
+//  head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm
+//  cmap if font is used with a simple font dict and not a CIDFont dict
+//
+// Other tables we need to keep for PDF rendering to support zoom in/out:
+//  bdat, bloc, ebdt, eblc, ebsc, gasp
+//
+// Special table:
+//  CFF - if you have this table then you shouldn't have a glyf table and this
+//        is the table with all the glyphs.  Shall skip subsetting completely
+//        since sfntly is not capable of subsetting it for now.
+//  post - extra info here for printing on PostScript printers but maybe not
+//         enough to outweigh the space taken by the names
+//
+// Tables to break apart:
+//  name - could throw away all but one language and one platform strings/ might
+//         throw away some of the name entries
+//  cmap - could strip out non-needed cmap subtables
+//       - format 4 subtable can be subsetted as well using sfntly
+//
+// Graphite tables:
+//  silf, glat, gloc, feat - should be okay to strip out
+//
+// Tables that can be discarded:
+//  OS/2 - everything here is for layout and description of the font that is
+//         elsewhere (some in the PDF objects)
+//  BASE, GDEF, GSUB, GPOS, JSTF - all used for layout
+//  kern - old style layout
+//  DSIG - this will be invalid after subsetting
+//  hdmx - layout
+//  PCLT - metadata that's not needed
+//  vmtx - layout
+//  vhea - layout
+//  VDMX
+//  VORG - not used by TT/OT - used by CFF
+//  hsty - would be surprised to see one of these - used on the Newton
+//  AAT tables - mort, morx, feat, acnt, bsin, just, lcar, fdsc, fmtx, prop,
+//               Zapf, opbd, trak, fvar, gvar, avar, cvar
+//             - these are all layout tables and once layout happens are not
+//               needed anymore
+//  LTSH - layout
+
+CALLER_ATTACH
+Font* SubsetterImpl::Subset(const IntegerSet& glyph_ids, GlyphTable* glyf,
+                            LocaTable* loca) {
+  // The const is initialized here to workaround VC bug of rendering all Tag::*
+  // as 0.  These tags represents the TTF tables that we will embed in subset
+  // font.
+  const int32_t TABLES_IN_SUBSET[] = {
+    Tag::head, Tag::hhea, Tag::loca, Tag::maxp, Tag::cvt,
+    Tag::prep, Tag::glyf, Tag::hmtx, Tag::fpgm, Tag::EBDT,
+    Tag::EBLC, Tag::EBSC, Tag::bdat, Tag::bloc, Tag::bhed,
+    Tag::cmap,  // Keep here for future tagged PDF development.
+    Tag::name,  // Keep here due to legal concerns: copyright info inside.
+  };
+
+  // Setup font builders we need.
+  FontBuilderPtr font_builder;
+  font_builder.Attach(factory_->NewFontBuilder());
+  IntegerSet remove_tags;
+
+  if (SetupGlyfBuilders(font_builder, glyf, loca, glyph_ids)) {
+    remove_tags.insert(Tag::glyf);
+    remove_tags.insert(Tag::loca);
+  }
+
+  // For old Apple bitmap fonts, they have only bdats and bhed is identical
+  // to head.  As a result, we can't remove bdat tables for those fonts.
+  int setup_result = SetupBitmapBuilders(font_, font_builder, glyph_ids);
+  if (setup_result == kRemoveBDATAndEBDT || setup_result == kRemoveEBDT) {
+    remove_tags.insert(Tag::EBDT);
+    remove_tags.insert(Tag::EBLC);
+    remove_tags.insert(Tag::EBSC);
+  }
+
+  if (setup_result == kRemoveBDAT || setup_result == kRemoveBDATAndEBDT) {
+    remove_tags.insert(Tag::bdat);
+    remove_tags.insert(Tag::bloc);
+    remove_tags.insert(Tag::bhed);
+  }
+
+  IntegerSet allowed_tags;
+  for (size_t i = 0; i < sizeof(TABLES_IN_SUBSET) / sizeof(int32_t); ++i) {
+    allowed_tags.insert(TABLES_IN_SUBSET[i]);
+  }
+
+  IntegerSet result;
+  std::set_difference(allowed_tags.begin(), allowed_tags.end(),
+                      remove_tags.begin(), remove_tags.end(),
+                      std::inserter(result, result.end()));
+  allowed_tags = result;
+
+  // Setup remaining builders.
+  for (IntegerSet::iterator i = allowed_tags.begin(), e = allowed_tags.end();
+                            i != e; ++i) {
+    Table* table = font_->GetTable(*i);
+    if (table) {
+      font_builder->NewTableBuilder(*i, table->ReadFontData());
+    }
+  }
+
+  return font_builder->Build();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sample/chromium/subsetter_impl.h b/cpp/src/sample/chromium/subsetter_impl.h
new file mode 100644
index 0000000..ffbf408
--- /dev/null
+++ b/cpp/src/sample/chromium/subsetter_impl.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// File is originally from Chromium third_party/sfntly/src/subsetter.
+// Use as test case in sfntly so that problems can be caught in upstream early.
+
+#ifndef SFNTLY_CPP_SRC_TEST_SUBSETTER_IMPL_H_
+#define SFNTLY_CPP_SRC_TEST_SUBSETTER_IMPL_H_
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+#include "sfntly/tag.h"
+
+namespace sfntly {
+
+// Smart pointer usage in sfntly:
+//
+// sfntly carries a smart pointer implementation like COM.  Ref-countable object
+// type inherits from RefCounted<>, which have AddRef and Release just like
+// IUnknown (but no QueryInterface).  Use a Ptr<> based smart pointer to hold
+// the object so that the object ref count is handled correctly.
+//
+// class Foo : public RefCounted<Foo> {
+//  public:
+//   static Foo* CreateInstance() {
+//     Ptr<Foo> obj = new Foo();  // ref count = 1
+//     return obj.detach();
+//   }
+// };
+// typedef Ptr<Foo> FooPtr;  // common short-hand notation
+// FooPtr obj;
+// obj.attach(Foo::CreatedInstance());  // ref count = 1
+// {
+//   FooPtr obj2 = obj;  // ref count = 2
+// }  // ref count = 1, obj2 out of scope
+// obj.release();  // ref count = 0, object destroyed
+
+class SubsetterImpl {
+ public:
+  SubsetterImpl();
+  ~SubsetterImpl();
+
+  bool LoadFont(const char* font_name,
+                const unsigned char* original_font,
+                size_t font_size);
+  int SubsetFont(const unsigned int* glyph_ids,
+                 size_t glyph_count,
+                 unsigned char** output_buffer);
+
+ private:
+  CALLER_ATTACH Font* Subset(const IntegerSet& glyph_ids,
+                             GlyphTable* glyf, LocaTable* loca);
+
+  FontFactoryPtr factory_;
+  FontPtr font_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_TEST_SUBSETTER_IMPL_H_
diff --git a/cpp/src/sample/subsetter/main.cc b/cpp/src/sample/subsetter/main.cc
new file mode 100644
index 0000000..19a3e0e
--- /dev/null
+++ b/cpp/src/sample/subsetter/main.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#if _MSC_VER > 12
+  #define _CRTDBG_MAP_ALLOC
+  #include <stdlib.h>
+  #include <crtdbg.h>
+#endif
+
+#include "sample/subsetter/subset_util.h"
+
+int main(int argc, char** argv) {
+#ifdef _CRTDBG_MAP_ALLOC
+  _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+  if (argc < 3) {
+    printf("Usage: subsetter <font file> <output file>\n");
+    return 0;
+  }
+
+  sfntly::SubsetUtil subset_util;
+  subset_util.Subset(argv[1], argv[2]);
+
+#ifdef _CRTDBG_MAP_ALLOC
+  _CrtDumpMemoryLeaks();
+#endif
+
+  return 0;
+}
diff --git a/cpp/src/sample/subsetter/subset_util.cc b/cpp/src/sample/subsetter/subset_util.cc
new file mode 100644
index 0000000..f35eb25
--- /dev/null
+++ b/cpp/src/sample/subsetter/subset_util.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Remove VC++ nag on fopen.
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "sample/subsetter/subset_util.h"
+
+#include <stdio.h>
+
+#include <vector>
+#include <memory>
+
+#include "sfntly/font.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/port/memory_output_stream.h"
+#include "sfntly/port/type.h"
+#include "sfntly/tag.h"
+#include "sfntly/tools/subsetter/subsetter.h"
+
+namespace sfntly {
+
+SubsetUtil::SubsetUtil() {
+}
+
+SubsetUtil::~SubsetUtil() {
+}
+
+void SubsetUtil::Subset(const char *input_file_path,
+                        const char *output_file_path) {
+  UNREFERENCED_PARAMETER(output_file_path);
+  ByteVector input_buffer;
+  FILE* input_file = fopen(input_file_path, "rb");
+  if (input_file == NULL) {
+    fprintf(stderr, "file not found\n");
+    return;
+  }
+  fseek(input_file, 0, SEEK_END);
+  size_t file_size = ftell(input_file);
+  fseek(input_file, 0, SEEK_SET);
+  input_buffer.resize(file_size);
+  size_t bytes_read = fread(&(input_buffer[0]), 1, file_size, input_file);
+  UNREFERENCED_PARAMETER(bytes_read);
+  fclose(input_file);
+
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+
+  FontArray font_array;
+  factory->LoadFonts(&input_buffer, &font_array);
+  if (font_array.empty() || font_array[0] == NULL)
+    return;
+
+  IntegerList glyphs;
+  for (int32_t i = 0; i < 10; i++) {
+    glyphs.push_back(i);
+  }
+  glyphs.push_back(11);
+  glyphs.push_back(10);
+
+  Ptr<Subsetter> subsetter = new Subsetter(font_array[0], factory);
+  subsetter->SetGlyphs(&glyphs);
+  IntegerSet remove_tables;
+  remove_tables.insert(Tag::DSIG);
+  subsetter->SetRemoveTables(&remove_tables);
+
+  FontBuilderPtr font_builder;
+  font_builder.Attach(subsetter->Subset());
+
+  FontPtr new_font;
+  new_font.Attach(font_builder->Build());
+
+  // TODO(arthurhsu): glyph renumbering/Loca table
+  // TODO(arthurhsu): alter CMaps
+
+  MemoryOutputStream output_stream;
+  factory->SerializeFont(new_font, &output_stream);
+
+  FILE* output_file = fopen(output_file_path, "wb");
+  fwrite(output_stream.Get(), 1, output_stream.Size(), output_file);
+  fflush(output_file);
+  fclose(output_file);
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sample/subsetter/subset_util.h b/cpp/src/sample/subsetter/subset_util.h
new file mode 100644
index 0000000..5eb4fe4
--- /dev/null
+++ b/cpp/src/sample/subsetter/subset_util.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SAMPLE_SUBSETTER_SUBSET_UTIL_H_
+#define SFNTLY_CPP_SRC_SAMPLE_SUBSETTER_SUBSET_UTIL_H_
+
+namespace sfntly {
+
+class SubsetUtil {
+ public:
+  SubsetUtil();
+  virtual ~SubsetUtil();
+
+  void Subset(const char* input_file_path, const char* output_file_path);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SAMPLE_SUBSETTER_SUBSET_UTIL_H_
diff --git a/cpp/src/sample/subtly/character_predicate.cc b/cpp/src/sample/subtly/character_predicate.cc
new file mode 100644
index 0000000..b9c6cc7
--- /dev/null
+++ b/cpp/src/sample/subtly/character_predicate.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/port/refcount.h"
+#include "subtly/character_predicate.h"
+
+namespace subtly {
+using namespace sfntly;
+
+// AcceptRange predicate
+AcceptRange::AcceptRange(int32_t start, int32_t end)
+    : start_(start),
+      end_(end) {
+}
+
+AcceptRange::~AcceptRange() {}
+
+bool AcceptRange::operator()(int32_t character) const {
+  return start_ <= character && character <= end_;
+}
+
+// AcceptSet predicate
+AcceptSet::AcceptSet(IntegerSet* characters)
+    : characters_(characters) {
+}
+
+AcceptSet::~AcceptSet() {
+  delete characters_;
+}
+
+bool AcceptSet::operator()(int32_t character) const {
+  return characters_->find(character) != characters_->end();
+}
+
+// AcceptAll predicate
+bool AcceptAll::operator()(int32_t character) const {
+  UNREFERENCED_PARAMETER(character);
+  return true;
+}
+}
diff --git a/cpp/src/sample/subtly/character_predicate.h b/cpp/src/sample/subtly/character_predicate.h
new file mode 100644
index 0000000..a6e3ea3
--- /dev/null
+++ b/cpp/src/sample/subtly/character_predicate.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_CHARACTER_PREDICATE_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_CHARACTER_PREDICATE_H_
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/port/type.h"
+
+namespace subtly {
+class CharacterPredicate : virtual public sfntly::RefCount {
+ public:
+  CharacterPredicate() {}
+  virtual ~CharacterPredicate() {}
+  virtual bool operator()(int32_t character) const = 0;
+};
+
+// All characters except for those between [start, end] are rejected
+class AcceptRange : public CharacterPredicate,
+                    public sfntly::RefCounted<AcceptRange> {
+ public:
+  AcceptRange(int32_t start, int32_t end);
+  ~AcceptRange();
+  virtual bool operator()(int32_t character) const;
+
+ private:
+  int32_t start_;
+  int32_t end_;
+};
+
+// All characters in IntegerSet
+// The set is OWNED by the predicate! Do not modify it.
+// It will be freed when the predicate is destroyed.
+class AcceptSet : public CharacterPredicate,
+                  public sfntly::RefCounted<AcceptSet> {
+ public:
+  explicit AcceptSet(sfntly::IntegerSet* characters);
+  ~AcceptSet();
+  virtual bool operator()(int32_t character) const;
+
+ private:
+  sfntly::IntegerSet* characters_;
+};
+
+// All characters
+class AcceptAll : public CharacterPredicate,
+                  public sfntly::RefCounted<AcceptAll> {
+ public:
+  AcceptAll() {}
+  ~AcceptAll() {}
+  virtual bool operator()(int32_t character) const;
+};
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_CHARACTER_PREDICATE_H_
diff --git a/cpp/src/sample/subtly/debug_main.cc b/cpp/src/sample/subtly/debug_main.cc
new file mode 100644
index 0000000..8324cde
--- /dev/null
+++ b/cpp/src/sample/subtly/debug_main.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <map>
+#include <utility>
+
+#include "sfntly/font.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/tag.h"
+#include "subtly/stats.h"
+#include "subtly/subsetter.h"
+#include "subtly/utils.h"
+
+using namespace subtly;
+
+void PrintUsage(const char* program_name) {
+  fprintf(stdout, "Usage: %s <input_font_file>\n", program_name);
+}
+
+int main(int argc, const char** argv) {
+  const char* program_name = argv[0];
+  if (argc < 2) {
+    PrintUsage(program_name);
+    exit(1);
+  }
+
+  const char* input_font_path = argv[1];
+  const char* output_font_path = argv[2];
+  FontPtr font;
+  font.Attach(subtly::LoadFont(input_font_path));
+
+  int32_t original_size = TotalFontSize(font);
+  Ptr<Subsetter> subsetter = new Subsetter(font, NULL);
+  Ptr<Font> new_font;
+  new_font.Attach(subsetter->Subset());
+  if (!new_font) {
+    fprintf(stdout, "Cannot create subset.\n");
+    return 0;
+  }
+
+  subtly::SerializeFont(output_font_path, new_font);
+  subtly::PrintComparison(stdout, font, new_font);
+  int32_t new_size = TotalFontSize(new_font);
+  fprintf(stdout, "Went from %d to %d: %lf%% of original\n",
+          original_size, new_size,
+          static_cast<double>(new_size) / original_size * 100);
+  return 0;
+}
diff --git a/cpp/src/sample/subtly/font_assembler.cc b/cpp/src/sample/subtly/font_assembler.cc
new file mode 100644
index 0000000..2f7cd11
--- /dev/null
+++ b/cpp/src/sample/subtly/font_assembler.cc
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "subtly/font_assembler.h"
+
+#include <stdio.h>
+
+#include <set>
+#include <map>
+
+#include "sfntly/tag.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/core/maximum_profile_table.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/refcount.h"
+#include "subtly/font_info.h"
+
+namespace subtly {
+using namespace sfntly;
+
+FontAssembler::FontAssembler(FontInfo* font_info,
+                             IntegerSet* table_blacklist)
+    : table_blacklist_(table_blacklist) {
+  font_info_ = font_info;
+  Initialize();
+}
+
+FontAssembler::FontAssembler(FontInfo* font_info)
+    : table_blacklist_(NULL) {
+  font_info_ = font_info;
+  Initialize();
+}
+
+void FontAssembler::Initialize() {
+  font_factory_.Attach(sfntly::FontFactory::GetInstance());
+  font_builder_.Attach(font_factory_->NewFontBuilder());
+}
+
+CALLER_ATTACH Font* FontAssembler::Assemble() {
+  // Assemble tables we can subset.
+  if (!AssembleCMapTable() || !AssembleGlyphAndLocaTables()) {
+    return NULL;
+  }
+  // For all other tables, either include them unmodified or don't at all.
+  const TableMap* common_table_map =
+      font_info_->GetTableMap(font_info_->fonts()->begin()->first);
+  for (TableMap::const_iterator it = common_table_map->begin(),
+           e = common_table_map->end(); it != e; ++it) {
+    if (table_blacklist_
+        && table_blacklist_->find(it->first) != table_blacklist_->end()) {
+      continue;
+    }
+    font_builder_->NewTableBuilder(it->first, it->second->ReadFontData());
+  }
+  return font_builder_->Build();
+}
+
+bool FontAssembler::AssembleCMapTable() {
+  // Creating the new CMapTable and the new format 4 CMap
+  Ptr<CMapTable::Builder> cmap_table_builder =
+      down_cast<CMapTable::Builder*>
+      (font_builder_->NewTableBuilder(Tag::cmap));
+  if (!cmap_table_builder)
+    return false;
+  Ptr<CMapTable::CMapFormat4::Builder> cmap_builder =
+      down_cast<CMapTable::CMapFormat4::Builder*>
+      (cmap_table_builder->NewCMapBuilder(CMapFormat::kFormat4,
+                                          CMapTable::WINDOWS_BMP));
+  if (!cmap_builder)
+    return false;
+  // Creating the segments and the glyph id array
+  CharacterMap* chars_to_glyph_ids = font_info_->chars_to_glyph_ids();
+  SegmentList* segment_list = new SegmentList;
+  IntegerList* glyph_id_array = new IntegerList;
+  int32_t last_chararacter = -2;
+  int32_t last_offset = 0;
+  Ptr<CMapTable::CMapFormat4::Builder::Segment> current_segment;
+
+  // For simplicity, we will have one segment per contiguous range.
+  // To test the algorithm, we've replaced the original CMap with the CMap
+  // generated by this code without removing any character.
+  // Tuffy.ttf: CMap went from 3146 to 3972 bytes (1.7% to 2.17% of file)
+  // AnonymousPro.ttf: CMap went from 1524 to 1900 bytes (0.96% to 1.2%)
+  for (CharacterMap::iterator it = chars_to_glyph_ids->begin(),
+           e = chars_to_glyph_ids->end(); it != e; ++it) {
+    int32_t character = it->first;
+    int32_t glyph_id = it->second.glyph_id();
+    if (character != last_chararacter + 1) {  // new segment
+      if (current_segment != NULL) {
+        current_segment->set_end_count(last_chararacter);
+        segment_list->push_back(current_segment);
+      }
+      // start_code = character
+      // end_code = -1 (unknown for now)
+      // id_delta = 0 (we don't use id_delta for this representation)
+      // id_range_offset = last_offset (offset into the glyph_id_array)
+      current_segment =
+          new CMapTable::CMapFormat4::Builder::
+          Segment(character, -1, 0, last_offset);
+    }
+    glyph_id_array->push_back(glyph_id);
+    last_offset += DataSize::kSHORT;
+    last_chararacter = character;
+  }
+  // The last segment is still open.
+  current_segment->set_end_count(last_chararacter);
+  segment_list->push_back(current_segment);
+  // Updating the id_range_offset for every segment.
+  for (int32_t i = 0, num_segs = segment_list->size(); i < num_segs; ++i) {
+    Ptr<CMapTable::CMapFormat4::Builder::Segment> segment = segment_list->at(i);
+    segment->set_id_range_offset(segment->id_range_offset()
+                                 + (num_segs - i + 1) * DataSize::kSHORT);
+  }
+  // Adding the final, required segment.
+  current_segment =
+      new CMapTable::CMapFormat4::Builder::Segment(0xffff, 0xffff, 1, 0);
+  segment_list->push_back(current_segment);
+  // Writing the segments and glyph id array to the CMap
+  cmap_builder->set_segments(segment_list);
+  cmap_builder->set_glyph_id_array(glyph_id_array);
+  delete segment_list;
+  delete glyph_id_array;
+  return true;
+}
+
+bool FontAssembler::AssembleGlyphAndLocaTables() {
+  Ptr<LocaTable::Builder> loca_table_builder =
+      down_cast<LocaTable::Builder*>
+      (font_builder_->NewTableBuilder(Tag::loca));
+  Ptr<GlyphTable::Builder> glyph_table_builder =
+      down_cast<GlyphTable::Builder*>
+      (font_builder_->NewTableBuilder(Tag::glyf));
+
+  GlyphIdSet* resolved_glyph_ids = font_info_->resolved_glyph_ids();
+  IntegerList loca_list;
+  // Basic sanity check: all LOCA tables are of the same size
+  // This is necessary but not suficient!
+  int32_t previous_size = -1;
+  for (FontIdMap::iterator it = font_info_->fonts()->begin();
+       it != font_info_->fonts()->end(); ++it) {
+    Ptr<LocaTable> loca_table =
+        down_cast<LocaTable*>(font_info_->GetTable(it->first, Tag::loca));
+    int32_t current_size = loca_table->header_length();
+    if (previous_size != -1 && current_size != previous_size) {
+      return false;
+    }
+    previous_size = current_size;
+  }
+
+  // Assuming all fonts referenced by the FontInfo are the subsets of the same
+  // font, their loca tables should all have the same sizes.
+  // We'll just get the size of the first font's LOCA table for simplicty.
+  Ptr<LocaTable> first_loca_table =
+    down_cast<LocaTable*>
+    (font_info_->GetTable(font_info_->fonts()->begin()->first, Tag::loca));
+  int32_t num_loca_glyphs = first_loca_table->num_glyphs();
+  loca_list.resize(num_loca_glyphs);
+  loca_list.push_back(0);
+  int32_t last_glyph_id = 0;
+  int32_t last_offset = 0;
+  GlyphTable::GlyphBuilderList* glyph_builders =
+      glyph_table_builder->GlyphBuilders();
+
+  for (GlyphIdSet::iterator it = resolved_glyph_ids->begin(),
+           e = resolved_glyph_ids->end(); it != e; ++it) {
+    // Get the glyph for this resolved_glyph_id.
+    int32_t resolved_glyph_id = it->glyph_id();
+    int32_t font_id = it->font_id();
+    // Get the LOCA table for the current glyph id.
+    Ptr<LocaTable> loca_table =
+        down_cast<LocaTable*>
+        (font_info_->GetTable(font_id, Tag::loca));
+    int32_t length = loca_table->GlyphLength(resolved_glyph_id);
+    int32_t offset = loca_table->GlyphOffset(resolved_glyph_id);
+
+    // Get the GLYF table for the current glyph id.
+    Ptr<GlyphTable> glyph_table =
+        down_cast<GlyphTable*>
+        (font_info_->GetTable(font_id, Tag::glyf));
+    GlyphPtr glyph;
+    glyph.Attach(glyph_table->GetGlyph(offset, length));
+
+    // The data reference by the glyph is copied into a new glyph and
+    // added to the glyph_builders belonging to the glyph_table_builder.
+    // When Build gets called, all the glyphs will be built.
+    Ptr<ReadableFontData> data = glyph->ReadFontData();
+    Ptr<WritableFontData> copy_data;
+    copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length()));
+    data->CopyTo(copy_data);
+    GlyphBuilderPtr glyph_builder;
+    glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data));
+    glyph_builders->push_back(glyph_builder);
+
+    // If there are missing glyphs between the last glyph_id and the
+    // current resolved_glyph_id, since the LOCA table needs to have the same
+    // size, the offset is kept the same.
+    for (int32_t i = last_glyph_id + 1; i <= resolved_glyph_id; ++i)
+      loca_list[i] = last_offset;
+    last_offset += length;
+    loca_list[resolved_glyph_id + 1] = last_offset;
+    last_glyph_id = resolved_glyph_id + 1;
+  }
+  // If there are missing glyph ids, their loca entries must all point
+  // to the same offset as the last valid glyph id making them all zero length.
+  for (int32_t i = last_glyph_id + 1; i <= num_loca_glyphs; ++i)
+    loca_list[i] = last_offset;
+  loca_table_builder->SetLocaList(&loca_list);
+  return true;
+}
+}
diff --git a/cpp/src/sample/subtly/font_assembler.h b/cpp/src/sample/subtly/font_assembler.h
new file mode 100644
index 0000000..c53c21f
--- /dev/null
+++ b/cpp/src/sample/subtly/font_assembler.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_ASSEMBLER_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_ASSEMBLER_H_
+
+#include <set>
+#include <map>
+
+#include "subtly/font_info.h"
+
+#include "sfntly/tag.h"
+#include "sfntly/font.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/refcount.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+
+namespace subtly {
+// Assembles FontInfo into font builders.
+// Does not take ownership of data passed to it.
+class FontAssembler : public sfntly::RefCounted<FontAssembler> {
+ public:
+  // font_info is the FontInfo which will be used for the new font
+  // table_blacklist is used to decide which tables to exclude from the
+  // final font.
+  FontAssembler(FontInfo* font_info, sfntly::IntegerSet* table_blacklist);
+  explicit FontAssembler(FontInfo* font_info);
+  ~FontAssembler() { }
+
+  // Assemble a new font from the font info object.
+  virtual CALLER_ATTACH sfntly::Font* Assemble();
+
+  sfntly::IntegerSet* table_blacklist() const { return table_blacklist_; }
+  void set_table_blacklist(sfntly::IntegerSet* table_blacklist) {
+    table_blacklist_ = table_blacklist;
+  }
+
+ protected:
+  virtual bool AssembleCMapTable();
+  virtual bool AssembleGlyphAndLocaTables();
+
+  virtual void Initialize();
+
+ private:
+  sfntly::Ptr<FontInfo> font_info_;
+  sfntly::Ptr<sfntly::FontFactory> font_factory_;
+  sfntly::Ptr<sfntly::Font::Builder> font_builder_;
+  sfntly::IntegerSet* table_blacklist_;
+};
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_ASSEMBLER_H_
diff --git a/cpp/src/sample/subtly/font_info.cc b/cpp/src/sample/subtly/font_info.cc
new file mode 100644
index 0000000..6eb6a38
--- /dev/null
+++ b/cpp/src/sample/subtly/font_info.cc
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "subtly/font_info.h"
+
+#include <stdio.h>
+
+#include <set>
+#include <map>
+
+#include "subtly/character_predicate.h"
+
+#include "sfntly/tag.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/core/maximum_profile_table.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/refcount.h"
+
+namespace subtly {
+using namespace sfntly;
+/******************************************************************************
+ * GlyphId class
+ ******************************************************************************/
+GlyphId::GlyphId(int32_t glyph_id, FontId font_id)
+    : glyph_id_(glyph_id),
+      font_id_(font_id) {
+}
+
+bool GlyphId::operator==(const GlyphId& other) const {
+  return glyph_id_ == other.glyph_id();
+}
+
+bool GlyphId::operator<(const GlyphId& other) const {
+  return glyph_id_ < other.glyph_id();
+}
+
+/******************************************************************************
+ * FontInfo class
+ ******************************************************************************/
+FontInfo::FontInfo()
+    : chars_to_glyph_ids_(new CharacterMap),
+      resolved_glyph_ids_(new GlyphIdSet),
+      fonts_(new FontIdMap) {
+}
+
+FontInfo::FontInfo(CharacterMap* chars_to_glyph_ids,
+                   GlyphIdSet* resolved_glyph_ids,
+                   FontIdMap* fonts) {
+  chars_to_glyph_ids_ = new CharacterMap(chars_to_glyph_ids->begin(),
+                                         chars_to_glyph_ids->end());
+  resolved_glyph_ids_ = new GlyphIdSet(resolved_glyph_ids->begin(),
+                                       resolved_glyph_ids->end());
+  fonts_ = new FontIdMap(fonts->begin(), fonts->end());
+}
+
+FontInfo::~FontInfo() {
+  delete chars_to_glyph_ids_;
+  delete resolved_glyph_ids_;
+  delete fonts_;
+}
+
+FontDataTable* FontInfo::GetTable(FontId font_id, int32_t tag) {
+  if (!fonts_)
+    return NULL;
+  FontIdMap::iterator it = fonts_->find(font_id);
+  if (it == fonts_->end())
+    return NULL;
+  return it->second->GetTable(tag);
+}
+
+const TableMap* FontInfo::GetTableMap(FontId font_id) {
+  if (!fonts_)
+    return NULL;
+  FontIdMap::iterator it = fonts_->find(font_id);
+  if (it == fonts_->end())
+    return NULL;
+  return it->second->GetTableMap();
+}
+
+void FontInfo::set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids) {
+  *chars_to_glyph_ids_ = *chars_to_glyph_ids;
+}
+
+void FontInfo::set_resolved_glyph_ids(GlyphIdSet* resolved_glyph_ids) {
+  *resolved_glyph_ids_ = *resolved_glyph_ids;
+}
+
+void FontInfo::set_fonts(FontIdMap* fonts) {
+  *fonts_ = *fonts;
+}
+
+/******************************************************************************
+ * FontSourcedInfoBuilder class
+ ******************************************************************************/
+FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font, FontId font_id)
+    : font_(font),
+      font_id_(font_id),
+      predicate_(NULL) {
+  Initialize();
+}
+
+FontSourcedInfoBuilder::FontSourcedInfoBuilder(Font* font,
+                                               FontId font_id,
+                                               CharacterPredicate* predicate)
+    : font_(font),
+      font_id_(font_id),
+      predicate_(predicate) {
+  Initialize();
+}
+
+void FontSourcedInfoBuilder::Initialize() {
+  Ptr<CMapTable> cmap_table = down_cast<CMapTable*>(font_->GetTable(Tag::cmap));
+  // We prefer Windows BMP format 4 cmaps.
+  cmap_.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP));
+  // But if none is found,
+  if (!cmap_) {
+    return;
+  }
+  loca_table_ = down_cast<LocaTable*>(font_->GetTable(Tag::loca));
+  glyph_table_ = down_cast<GlyphTable*>(font_->GetTable(Tag::glyf));
+}
+
+CALLER_ATTACH FontInfo* FontSourcedInfoBuilder::GetFontInfo() {
+  CharacterMap* chars_to_glyph_ids = new CharacterMap;
+  bool success = GetCharacterMap(chars_to_glyph_ids);
+  if (!success) {
+    delete chars_to_glyph_ids;
+#if defined (SUBTLY_DEBUG)
+    fprintf(stderr, "Error creating character map.\n");
+#endif
+    return NULL;
+  }
+  GlyphIdSet* resolved_glyph_ids = new GlyphIdSet;
+  success = ResolveCompositeGlyphs(chars_to_glyph_ids, resolved_glyph_ids);
+  if (!success) {
+    delete chars_to_glyph_ids;
+    delete resolved_glyph_ids;
+#if defined (SUBTLY_DEBUG)
+    fprintf(stderr, "Error resolving composite glyphs.\n");
+#endif
+    return NULL;
+  }
+  Ptr<FontInfo> font_info = new FontInfo;
+  font_info->set_chars_to_glyph_ids(chars_to_glyph_ids);
+  font_info->set_resolved_glyph_ids(resolved_glyph_ids);
+  FontIdMap* font_id_map = new FontIdMap;
+  font_id_map->insert(std::make_pair(font_id_, font_));
+  font_info->set_fonts(font_id_map);
+  delete chars_to_glyph_ids;
+  delete resolved_glyph_ids;
+  delete font_id_map;
+  return font_info.Detach();
+}
+
+bool FontSourcedInfoBuilder::GetCharacterMap(CharacterMap* chars_to_glyph_ids) {
+  if (!cmap_ || !chars_to_glyph_ids)
+    return false;
+  chars_to_glyph_ids->clear();
+  CMapTable::CMap::CharacterIterator* character_iterator = cmap_->Iterator();
+  if (!character_iterator)
+    return false;
+  while (character_iterator->HasNext()) {
+    int32_t character = character_iterator->Next();
+    if (!predicate_ || (*predicate_)(character)) {
+      chars_to_glyph_ids->insert
+          (std::make_pair(character,
+                          GlyphId(cmap_->GlyphId(character), font_id_)));
+    }
+  }
+  delete character_iterator;
+  return true;
+}
+
+bool
+FontSourcedInfoBuilder::ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids,
+                                               GlyphIdSet* resolved_glyph_ids) {
+  if (!chars_to_glyph_ids || !resolved_glyph_ids)
+    return false;
+  resolved_glyph_ids->clear();
+  resolved_glyph_ids->insert(GlyphId(0, font_id_));
+  IntegerSet* unresolved_glyph_ids = new IntegerSet;
+  // Since composite glyph elements might themselves be composite, we would need
+  // to recursively resolve the elements too. To avoid the recursion we
+  // create two sets, |unresolved_glyph_ids| for the unresolved glyphs,
+  // initially containing all the ids and |resolved_glyph_ids|, initially empty.
+  // We'll remove glyph ids from |unresolved_glyph_ids| until it is empty and,
+  // if the glyph is composite, add its elements to the unresolved set.
+  for (CharacterMap::iterator it = chars_to_glyph_ids->begin(),
+           e = chars_to_glyph_ids->end(); it != e; ++it) {
+    unresolved_glyph_ids->insert(it->second.glyph_id());
+  }
+  // As long as there are unresolved glyph ids.
+  while (!unresolved_glyph_ids->empty()) {
+    // Get the corresponding glyph.
+    int32_t glyph_id = *(unresolved_glyph_ids->begin());
+    unresolved_glyph_ids->erase(unresolved_glyph_ids->begin());
+    if (glyph_id < 0 || glyph_id > loca_table_->num_glyphs()) {
+#if defined (SUBTLY_DEBUG)
+      fprintf(stderr, "%d larger than %d or smaller than 0\n", glyph_id,
+              loca_table_->num_glyphs());
+#endif
+      continue;
+    }
+    int32_t length = loca_table_->GlyphLength(glyph_id);
+    if (length == 0) {
+#if defined (SUBTLY_DEBUG)
+      fprintf(stderr, "Zero length glyph %d\n", glyph_id);
+#endif
+      continue;
+    }
+    int32_t offset = loca_table_->GlyphOffset(glyph_id);
+    GlyphPtr glyph;
+    glyph.Attach(glyph_table_->GetGlyph(offset, length));
+    if (glyph == NULL) {
+#if defined (SUBTLY_DEBUG)
+      fprintf(stderr, "GetGlyph returned NULL for %d\n", glyph_id);
+#endif
+      continue;
+    }
+    // Mark the glyph as resolved.
+    resolved_glyph_ids->insert(GlyphId(glyph_id, font_id_));
+    // If it is composite, add all its components to the unresolved glyph set.
+    if (glyph->GlyphType() == GlyphType::kComposite) {
+      Ptr<GlyphTable::CompositeGlyph> composite_glyph =
+          down_cast<GlyphTable::CompositeGlyph*>(glyph.p_);
+      int32_t num_glyphs = composite_glyph->NumGlyphs();
+      for (int32_t i = 0; i < num_glyphs; ++i) {
+        int32_t glyph_id = composite_glyph->GlyphIndex(i);
+        if (resolved_glyph_ids->find(GlyphId(glyph_id, -1))
+            == resolved_glyph_ids->end()) {
+          unresolved_glyph_ids->insert(glyph_id);
+        }
+      }
+    }
+  }
+  delete unresolved_glyph_ids;
+  return true;
+}
+}
diff --git a/cpp/src/sample/subtly/font_info.h b/cpp/src/sample/subtly/font_info.h
new file mode 100644
index 0000000..6f42d73
--- /dev/null
+++ b/cpp/src/sample/subtly/font_info.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_INFO_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_INFO_H_
+
+#include <map>
+#include <set>
+
+#include "sfntly/font.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/refcount.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+
+namespace subtly {
+class CharacterPredicate;
+
+typedef int32_t FontId;
+typedef std::map<FontId, sfntly::Ptr<sfntly::Font> > FontIdMap;
+
+// Glyph id pair that contains the loca table glyph id as well as the
+// font id that has the glyph table this glyph belongs to.
+class GlyphId {
+ public:
+  GlyphId(int32_t glyph_id, FontId font_id);
+  ~GlyphId() {}
+
+  bool operator==(const GlyphId& other) const;
+  bool operator<(const GlyphId& other) const;
+
+  int32_t glyph_id() const { return glyph_id_; }
+  void set_glyph_id(const int32_t glyph_id) { glyph_id_ = glyph_id; }
+  FontId font_id() const { return font_id_; }
+  void set_font_id(const FontId font_id) { font_id_ = font_id; }
+
+ private:
+  int32_t glyph_id_;
+  FontId font_id_;
+};
+
+typedef std::map<int32_t, GlyphId> CharacterMap;
+typedef std::set<GlyphId> GlyphIdSet;
+
+// Font information used for FontAssembler in the construction of a new font.
+// Will make copies of character map, glyph id set and font id map.
+class FontInfo : public sfntly::RefCounted<FontInfo> {
+ public:
+  // Empty FontInfo object.
+  FontInfo();
+  // chars_to_glyph_ids maps characters to GlyphIds for CMap construction
+  // resolved_glyph_ids defines GlyphIds which should be in the final font
+  // fonts is a map of font ids to fonts to reference any needed table
+  FontInfo(CharacterMap* chars_to_glyph_ids,
+           GlyphIdSet* resolved_glyph_ids,
+           FontIdMap* fonts);
+  virtual ~FontInfo();
+
+  // Gets the table with the specified tag from the font corresponding to
+  // font_id or NULL if there is no such font/table.
+  // font_id is the id of the font that contains the table
+  // tag identifies the table to be obtained
+  virtual sfntly::FontDataTable* GetTable(FontId font_id, int32_t tag);
+  // Gets the table map of the font whose id is font_id
+  virtual const sfntly::TableMap* GetTableMap(FontId);
+
+  CharacterMap* chars_to_glyph_ids() const { return chars_to_glyph_ids_; }
+  // Takes ownership of the chars_to_glyph_ids CharacterMap.
+  void set_chars_to_glyph_ids(CharacterMap* chars_to_glyph_ids);
+  GlyphIdSet* resolved_glyph_ids() const { return resolved_glyph_ids_; }
+  // Takes ownership of the glyph_ids GlyphIdSet.
+  void set_resolved_glyph_ids(GlyphIdSet* glyph_ids);
+  FontIdMap* fonts() const { return fonts_; }
+  // Takes ownership of the fonts FontIdMap.
+  void set_fonts(FontIdMap* fonts);
+
+ private:
+  CharacterMap* chars_to_glyph_ids_;
+  GlyphIdSet* resolved_glyph_ids_;
+  FontIdMap* fonts_;
+};
+
+// FontSourcedInfoBuilder is used to create a FontInfo object from a Font
+// optionally specifying a CharacterPredicate to filter out some of
+// the font's characters.
+// It does not take ownership or copy the values its constructor receives.
+class FontSourcedInfoBuilder :
+      public sfntly::RefCounted<FontSourcedInfoBuilder> {
+ public:
+  FontSourcedInfoBuilder(sfntly::Font* font, FontId font_id);
+  FontSourcedInfoBuilder(sfntly::Font* font,
+                         FontId font_id,
+                         CharacterPredicate* predicate);
+  virtual ~FontSourcedInfoBuilder() { }
+
+  virtual CALLER_ATTACH FontInfo* GetFontInfo();
+
+ protected:
+  bool GetCharacterMap(CharacterMap* chars_to_glyph_ids);
+  bool ResolveCompositeGlyphs(CharacterMap* chars_to_glyph_ids,
+                              GlyphIdSet* resolved_glyph_ids);
+  void Initialize();
+
+ private:
+  sfntly::Ptr<sfntly::Font> font_;
+  FontId font_id_;
+  CharacterPredicate* predicate_;
+
+  sfntly::Ptr<sfntly::CMapTable::CMap> cmap_;
+  sfntly::Ptr<sfntly::LocaTable> loca_table_;
+  sfntly::Ptr<sfntly::GlyphTable> glyph_table_;
+};
+}
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_FONT_INFO_H_
diff --git a/cpp/src/sample/subtly/merger.cc b/cpp/src/sample/subtly/merger.cc
new file mode 100644
index 0000000..7875c2d
--- /dev/null
+++ b/cpp/src/sample/subtly/merger.cc
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "subtly/merger.h"
+
+#include <stdio.h>
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "subtly/character_predicate.h"
+#include "subtly/font_assembler.h"
+#include "subtly/font_info.h"
+#include "subtly/utils.h"
+
+namespace subtly {
+using namespace sfntly;
+
+/******************************************************************************
+ * Merger class
+ ******************************************************************************/
+Merger::Merger(FontArray* fonts) {
+  if (!fonts) {
+    return;
+  }
+  int32_t num_fonts = fonts->size();
+  for (int32_t i = 0; i < num_fonts; ++i) {
+    fonts_.insert(std::make_pair(i, fonts->at(i)));
+  }
+}
+
+CALLER_ATTACH Font* Merger::Merge() {
+  Ptr<FontInfo> merged_info;
+  merged_info.Attach(MergeFontInfos());
+  if (!merged_info) {
+#if defined (SUBTLY_DEBUG)
+    fprintf(stderr, "Could not create merged font info\n");
+#endif
+    return NULL;
+  }
+  Ptr<FontAssembler> font_assembler = new FontAssembler(merged_info);
+  return font_assembler->Assemble();
+}
+
+CALLER_ATTACH FontInfo* Merger::MergeFontInfos() {
+  Ptr<FontInfo> font_info = new FontInfo;
+  font_info->set_fonts(&fonts_);
+  for (FontIdMap::iterator it = fonts_.begin(),
+           e = fonts_.end(); it != e; ++it) {
+    Ptr<FontSourcedInfoBuilder> info_builder =
+        new FontSourcedInfoBuilder(it->second, it->first, NULL);
+    Ptr<FontInfo> current_font_info;
+    current_font_info.Attach(info_builder->GetFontInfo());
+    if (!current_font_info) {
+#if defined (SUBTLY_DEBUG)
+      fprintf(stderr, "Couldn't create font info. "
+              "No subset will be generated.\n");
+#endif
+      return NULL;
+    }
+    font_info->chars_to_glyph_ids()->insert(
+        current_font_info->chars_to_glyph_ids()->begin(),
+        current_font_info->chars_to_glyph_ids()->end());
+    font_info->resolved_glyph_ids()->insert(
+        current_font_info->resolved_glyph_ids()->begin(),
+        current_font_info->resolved_glyph_ids()->end());
+#if defined (SUBTLY_DEBUG)
+    fprintf(stderr, "Counts: chars_to_glyph_ids: %d; resoved_glyph_ids: %d\n",
+            font_info->chars_to_glyph_ids()->size(),
+            font_info->resolved_glyph_ids()->size());
+#endif
+  }
+  return font_info.Detach();
+}
+}
diff --git a/cpp/src/sample/subtly/merger.h b/cpp/src/sample/subtly/merger.h
new file mode 100644
index 0000000..43764a8
--- /dev/null
+++ b/cpp/src/sample/subtly/merger.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_MERGER_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_MERGER_H_
+
+#include "subtly/character_predicate.h"
+#include "subtly/font_info.h"
+
+namespace sfntly {
+class Font;
+}
+
+namespace subtly {
+// Merges the subsets in the font array into a single font.
+class Merger : public sfntly::RefCounted<Merger> {
+ public:
+  explicit Merger(sfntly::FontArray* fonts);
+  virtual ~Merger() { }
+
+  // Performs merging returning the subsetted font.
+  virtual CALLER_ATTACH sfntly::Font* Merge();
+
+ protected:
+  virtual CALLER_ATTACH FontInfo* MergeFontInfos();
+
+ private:
+  FontIdMap fonts_;
+};
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_MERGER_H_
diff --git a/cpp/src/sample/subtly/merger_main.cc b/cpp/src/sample/subtly/merger_main.cc
new file mode 100644
index 0000000..a977aa7
--- /dev/null
+++ b/cpp/src/sample/subtly/merger_main.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <map>
+#include <utility>
+
+#include "sfntly/font.h"
+#include "subtly/merger.h"
+#include "subtly/stats.h"
+#include "subtly/utils.h"
+
+using namespace subtly;
+
+void PrintUsage(const char* program_name) {
+  fprintf(stdout, "Usage: %s <input_font_file1> <input_font_file2> ..."
+          "<input_font_filen> <output_font_file>\n",
+          program_name);
+}
+
+void CheckLoading(const char* font_path, Font* font) {
+  if (!font || font->num_tables() == 0) {
+    fprintf(stderr, "Could not load font %s. Terminating.\n", font_path);
+    exit(1);
+  }
+}
+
+int main(int argc, const char** argv) {
+  if (argc < 3) {
+    PrintUsage(argv[0]);
+    exit(1);
+  }
+
+  FontArray fonts;
+  for (int32_t i = 1; i < argc - 1; ++i) {
+    Ptr<Font> font;
+    font.Attach(LoadFont(argv[i]));
+    CheckLoading(argv[i], font);
+    fonts.push_back(font);
+  }
+
+  Ptr<Merger> merger = new Merger(&fonts);
+  FontPtr new_font;
+  new_font.Attach(merger->Merge());
+
+  fprintf(stderr, "Serializing font to %s\n", argv[argc - 1]);
+  SerializeFont(argv[argc - 1], new_font);
+  if (!new_font) {
+    fprintf(stdout, "Cannot create merged font.\n");
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/cpp/src/sample/subtly/stats.cc b/cpp/src/sample/subtly/stats.cc
new file mode 100644
index 0000000..769f691
--- /dev/null
+++ b/cpp/src/sample/subtly/stats.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include "sfntly/font.h"
+#include "sfntly/table/table.h"
+#include "sfntly/tag.h"
+#include "subtly/stats.h"
+
+namespace subtly {
+using namespace sfntly;
+
+int32_t TotalFontSize(Font* font) {
+  int32_t size = 0;
+  const TableMap* table_map = font->GetTableMap();
+  for (TableMap::const_iterator it = table_map->begin(),
+           e = table_map->end(); it != e; ++it) {
+    size += it->second->DataLength();
+  }
+  return size;
+}
+
+double TableSizePercent(Font* font, int32_t tag) {
+  TablePtr table = font->GetTable(tag);
+  return static_cast<double>(table->DataLength()) / TotalFontSize(font) * 100;
+}
+
+void PrintComparison(FILE* out, Font* font, Font* new_font) {
+  fprintf(out, "====== Table Comparison (original v. subset) ======\n");
+  const TableMap* tables = font->GetTableMap();
+  for (TableMap::const_iterator it = tables->begin(),
+           e = tables->end(); it != e; ++it) {
+    char *name = TagToString(it->first);
+    int32_t size = it->second->DataLength();
+    fprintf(out, "-- %s: %d (%lf%%) ", name, size,
+            TableSizePercent(font, it->first));
+    delete[] name;
+
+    Ptr<FontDataTable> new_table = new_font->GetTable(it->first);
+    int32_t new_size = 0;
+    double size_percent = 0;
+    if (new_table) {
+      new_size = new_table->DataLength();
+      size_percent = subtly::TableSizePercent(new_font, it->first);
+    }
+
+    if (new_size == size) {
+      fprintf(out, "| same size\n");
+    } else {
+      fprintf(out, "-> %d (%lf%%) | %lf%% of original\n", new_size,
+              size_percent, static_cast<double>(new_size) / size * 100);
+    }
+  }
+}
+
+void PrintStats(FILE* out, Font* font) {
+  fprintf(out, "====== Table Stats ======\n");
+  const TableMap* tables = font->GetTableMap();
+  for (TableMap::const_iterator it = tables->begin(),
+           e = tables->end(); it != e; ++it) {
+    char *name = TagToString(it->first);
+    int32_t size = it->second->DataLength();
+    fprintf(out, "-- %s: %d (%lf%%)\n", name, size,
+            TableSizePercent(font, it->first));
+    delete[] name;
+  }
+}
+}
diff --git a/cpp/src/sample/subtly/stats.h b/cpp/src/sample/subtly/stats.h
new file mode 100644
index 0000000..89ef2ae
--- /dev/null
+++ b/cpp/src/sample/subtly/stats.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_STATS_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_STATS_H_
+
+#include <stdio.h>
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+class Font;
+}
+
+namespace subtly {
+using namespace sfntly;
+
+int32_t TotalFontSize(Font* font);
+
+double TableSizePercent(Font* font, int32_t tag);
+
+void PrintComparison(FILE* out, Font* font, Font* new_font);
+
+void PrintStats(FILE* out, Font* font);
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_STATS_H_
diff --git a/cpp/src/sample/subtly/subsetter.cc b/cpp/src/sample/subtly/subsetter.cc
new file mode 100644
index 0000000..d09627c
--- /dev/null
+++ b/cpp/src/sample/subtly/subsetter.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "subtly/subsetter.h"
+
+#include <stdio.h>
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/tag.h"
+#include "subtly/character_predicate.h"
+#include "subtly/font_assembler.h"
+#include "subtly/font_info.h"
+#include "subtly/utils.h"
+
+namespace subtly {
+using namespace sfntly;
+
+/******************************************************************************
+ * Subsetter class
+ ******************************************************************************/
+Subsetter::Subsetter(Font* font, CharacterPredicate* predicate)
+    : font_(font),
+      predicate_(predicate) {
+}
+
+Subsetter::Subsetter(const char* font_path, CharacterPredicate* predicate)
+    : predicate_(predicate) {
+  font_.Attach(LoadFont(font_path));
+}
+
+CALLER_ATTACH Font* Subsetter::Subset() {
+  Ptr<FontSourcedInfoBuilder> info_builder =
+      new FontSourcedInfoBuilder(font_, 0, predicate_);
+
+  Ptr<FontInfo> font_info;
+  font_info.Attach(info_builder->GetFontInfo());
+  if (!font_info) {
+#if defined (SUBTLY_DEBUG)
+    fprintf(stderr,
+            "Couldn't create font info. No subset will be generated.\n");
+#endif
+    return NULL;
+  }
+  IntegerSet* table_blacklist = new IntegerSet;
+  table_blacklist->insert(Tag::DSIG);
+  Ptr<FontAssembler> font_assembler = new FontAssembler(font_info,
+                                                        table_blacklist);
+  Ptr<Font> font_subset;
+  font_subset.Attach(font_assembler->Assemble());
+  delete table_blacklist;
+  return font_subset.Detach();
+}
+}
diff --git a/cpp/src/sample/subtly/subsetter.h b/cpp/src/sample/subtly/subsetter.h
new file mode 100644
index 0000000..a93747f
--- /dev/null
+++ b/cpp/src/sample/subtly/subsetter.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_SUBSETTER_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_SUBSETTER_H_
+
+#include "sfntly/font.h"
+// Cannot remove this header due to Ptr<T> instantiation issue
+#include "subtly/character_predicate.h"
+
+namespace subtly {
+// Subsets a given font using a character predicate.
+class Subsetter : public sfntly::RefCounted<Subsetter> {
+ public:
+  Subsetter(sfntly::Font* font, CharacterPredicate* predicate);
+  Subsetter(const char* font_path, CharacterPredicate* predicate);
+  virtual ~Subsetter() { }
+
+  // Performs subsetting returning the subsetted font.
+  virtual CALLER_ATTACH sfntly::Font* Subset();
+
+ private:
+  sfntly::Ptr<sfntly::Font> font_;
+  sfntly::Ptr<CharacterPredicate> predicate_;
+};
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_SUBSETTER_H_
diff --git a/cpp/src/sample/subtly/subsetter_main.cc b/cpp/src/sample/subtly/subsetter_main.cc
new file mode 100644
index 0000000..d438148
--- /dev/null
+++ b/cpp/src/sample/subtly/subsetter_main.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <map>
+#include <utility>
+
+#include "sfntly/font.h"
+#include "subtly/character_predicate.h"
+#include "subtly/stats.h"
+#include "subtly/subsetter.h"
+#include "subtly/utils.h"
+
+using namespace subtly;
+
+void PrintUsage(const char* program_name) {
+  fprintf(stdout, "Usage: %s <input_font_file> <output_font_file>"
+          "<start_char> <end_char>\n", program_name);
+}
+
+int main(int argc, const char** argv) {
+  const char* program_name = argv[0];
+  if (argc < 5) {
+    PrintUsage(program_name);
+    exit(1);
+  }
+
+  const char* input_font_path = argv[1];
+  const char* output_font_path = argv[2];
+  FontPtr font;
+  font.Attach(subtly::LoadFont(input_font_path));
+  if (font->num_tables() == 0) {
+    fprintf(stderr, "Could not load font %s.\n", input_font_path);
+    exit(1);
+  }
+
+  const char* start_char = argv[3];
+  const char* end_char = argv[4];
+  if (start_char[1] != 0) {
+    fprintf(stderr, "Start character %c invalid.\n", start_char[0]);
+    exit(1);
+  }
+  if (end_char[1] != 0) {
+    fprintf(stderr, "Start character %c invalid.\n", end_char[0]);
+    exit(1);
+  }
+  int32_t original_size = TotalFontSize(font);
+
+
+  Ptr<CharacterPredicate> range_predicate =
+      new AcceptRange(start_char[0], end_char[0]);
+  Ptr<Subsetter> subsetter = new Subsetter(font, range_predicate);
+  Ptr<Font> new_font;
+  new_font.Attach(subsetter->Subset());
+  if (!new_font) {
+    fprintf(stdout, "Cannot create subset.\n");
+    return 0;
+  }
+
+  subtly::SerializeFont(output_font_path, new_font);
+  subtly::PrintComparison(stdout, font, new_font);
+  int32_t new_size = TotalFontSize(new_font);
+  fprintf(stdout, "Went from %d to %d: %lf%% of original\n",
+          original_size, new_size,
+          static_cast<double>(new_size) / original_size * 100);
+  return 0;
+}
diff --git a/cpp/src/sample/subtly/utils.cc b/cpp/src/sample/subtly/utils.cc
new file mode 100644
index 0000000..3c204d3
--- /dev/null
+++ b/cpp/src/sample/subtly/utils.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "subtly/utils.h"
+
+#include "sfntly/data/growable_memory_byte_array.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/port/file_input_stream.h"
+#include "sfntly/port/memory_output_stream.h"
+
+namespace subtly {
+using namespace sfntly;
+
+CALLER_ATTACH Font* LoadFont(const char* font_path) {
+  Ptr<FontFactory> font_factory;
+  font_factory.Attach(FontFactory::GetInstance());
+  FontArray fonts;
+  LoadFonts(font_path, font_factory, &fonts);
+  return fonts[0].Detach();
+}
+
+CALLER_ATTACH Font::Builder* LoadFontBuilder(const char* font_path) {
+  FontFactoryPtr font_factory;
+  font_factory.Attach(FontFactory::GetInstance());
+  FontBuilderArray builders;
+  LoadFontBuilders(font_path, font_factory, &builders);
+  return builders[0].Detach();
+}
+
+void LoadFonts(const char* font_path, FontFactory* factory, FontArray* fonts) {
+  FileInputStream input_stream;
+  input_stream.Open(font_path);
+  factory->LoadFonts(&input_stream, fonts);
+  input_stream.Close();
+}
+
+void LoadFontBuilders(const char* font_path,
+                      FontFactory* factory,
+                      FontBuilderArray* builders) {
+  FileInputStream input_stream;
+  input_stream.Open(font_path);
+  factory->LoadFontsForBuilding(&input_stream, builders);
+  input_stream.Close();
+}
+
+bool SerializeFont(const char* font_path, Font* font) {
+  if (!font_path)
+    return false;
+  FontFactoryPtr font_factory;
+  font_factory.Attach(FontFactory::GetInstance());
+  return SerializeFont(font_path, font_factory, font);
+}
+
+bool SerializeFont(const char* font_path, FontFactory* factory, Font* font) {
+  if (!font_path || !factory || !font)
+    return false;
+  // Serializing the font to a stream.
+  MemoryOutputStream output_stream;
+  factory->SerializeFont(font, &output_stream);
+  // Serializing the stream to a file.
+  FILE* output_file = NULL;
+#if defined WIN32
+  fopen_s(&output_file, font_path, "wb");
+#else
+  output_file = fopen(font_path, "wb");
+#endif
+  if (output_file == reinterpret_cast<FILE*>(NULL))
+    return false;
+  for (size_t i = 0; i < output_stream.Size(); ++i) {
+    fwrite(&(output_stream.Get()[i]), 1, 1, output_file);
+  }
+  fflush(output_file);
+  fclose(output_file);
+  return true;
+}
+};
diff --git a/cpp/src/sample/subtly/utils.h b/cpp/src/sample/subtly/utils.h
new file mode 100644
index 0000000..ba9f0d4
--- /dev/null
+++ b/cpp/src/sample/subtly/utils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_UTILS_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_UTILS_H_
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+
+namespace subtly {
+CALLER_ATTACH sfntly::Font* LoadFont(const char* font_path);
+CALLER_ATTACH sfntly::Font::Builder* LoadFontBuilder(const char* font_path);
+
+void LoadFonts(const char* font_path, sfntly::FontFactory* factory,
+               sfntly::FontArray* fonts);
+void LoadFontBuilders(const char* font_path,
+                      sfntly::FontFactory* factory,
+                      sfntly::FontBuilderArray* builders);
+
+bool SerializeFont(const char* font_path, sfntly::Font* font);
+bool SerializeFont(const char* font_path, sfntly::FontFactory* factory,
+                   sfntly::Font* font);
+}
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SAMPLE_SUBTLY_UTILS_H_
diff --git a/cpp/src/sfntly/data/byte_array.cc b/cpp/src/sfntly/data/byte_array.cc
new file mode 100644
index 0000000..915a40c
--- /dev/null
+++ b/cpp/src/sfntly/data/byte_array.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/data/byte_array.h"
+
+#include <algorithm>
+
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+
+const int32_t ByteArray::COPY_BUFFER_SIZE = 8192;
+
+ByteArray::~ByteArray() {}
+
+int32_t ByteArray::Length() { return filled_length_; }
+int32_t ByteArray::Size() { return storage_length_; }
+
+int32_t ByteArray::SetFilledLength(int32_t filled_length) {
+  filled_length_ = std::min<int32_t>(filled_length, storage_length_);
+  return filled_length_;
+}
+
+int32_t ByteArray::Get(int32_t index) {
+  return InternalGet(index) & 0xff;
+}
+
+int32_t ByteArray::Get(int32_t index, ByteVector* b) {
+  assert(b);
+  return Get(index, &((*b)[0]), 0, b->size());
+}
+
+int32_t ByteArray::Get(int32_t index,
+                       byte_t* b,
+                       int32_t offset,
+                       int32_t length) {
+  assert(b);
+  if (index < 0 || index >= filled_length_) {
+    return 0;
+  }
+  int32_t actual_length = std::min<int32_t>(length, filled_length_ - index);
+  return InternalGet(index, b, offset, actual_length);
+}
+
+void ByteArray::Put(int32_t index, byte_t b) {
+  if (index < 0 || index >= Size()) {
+#if defined (SFNTLY_NO_EXCEPTION)
+    return;
+#else
+    throw IndexOutOfBoundException(
+        "Attempt to write outside the bounds of the data");
+#endif
+  }
+  InternalPut(index, b);
+  filled_length_ = std::max<int32_t>(filled_length_, index + 1);
+}
+
+int32_t ByteArray::Put(int index, ByteVector* b) {
+  assert(b);
+  return Put(index, &((*b)[0]), 0, b->size());
+}
+
+int32_t ByteArray::Put(int32_t index,
+                       byte_t* b,
+                       int32_t offset,
+                       int32_t length) {
+  assert(b);
+  if (index < 0 || index >= Size()) {
+#if defined (SFNTLY_NO_EXCEPTION)
+    return 0;
+#else
+    throw IndexOutOfBoundException(
+        "Attempt to write outside the bounds of the data");
+#endif
+  }
+  int32_t actual_length = std::min<int32_t>(length, Size() - index);
+  int32_t bytes_written = InternalPut(index, b, offset, actual_length);
+  filled_length_ = std::max<int32_t>(filled_length_, index + bytes_written);
+  return bytes_written;
+}
+
+int32_t ByteArray::CopyTo(ByteArray* array) {
+  return CopyTo(array, 0, Length());
+}
+
+int32_t ByteArray::CopyTo(ByteArray* array, int32_t offset, int32_t length) {
+  return CopyTo(0, array, offset, length);
+}
+
+int32_t ByteArray::CopyTo(int32_t dst_offset, ByteArray* array,
+                          int32_t src_offset, int32_t length) {
+  assert(array);
+  if (array->Size() < dst_offset + length) {  // insufficient space
+    return -1;
+  }
+
+  ByteVector b(COPY_BUFFER_SIZE);
+  int32_t bytes_read = 0;
+  int32_t index = 0;
+  int32_t remaining_length = length;
+  int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
+  while ((bytes_read =
+              Get(index + src_offset, &(b[0]), 0, buffer_length)) > 0) {
+    int bytes_written = array->Put(index + dst_offset, &(b[0]), 0, bytes_read);
+    UNREFERENCED_PARAMETER(bytes_written);
+    index += bytes_read;
+    remaining_length -= bytes_read;
+    buffer_length = std::min<int32_t>(b.size(), remaining_length);
+  }
+  return index;
+}
+
+int32_t ByteArray::CopyTo(OutputStream* os) {
+    return CopyTo(os, 0, Length());
+}
+
+int32_t ByteArray::CopyTo(OutputStream* os, int32_t offset, int32_t length) {
+  ByteVector b(COPY_BUFFER_SIZE);
+  int32_t bytes_read = 0;
+  int32_t index = 0;
+  int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
+  while ((bytes_read = Get(index + offset, &(b[0]), 0, buffer_length)) > 0) {
+    os->Write(&b, 0, bytes_read);
+    index += bytes_read;
+    buffer_length = std::min<int32_t>(b.size(), length - index);
+  }
+  return index;
+}
+
+bool ByteArray::CopyFrom(InputStream* is, int32_t length) {
+  ByteVector b(COPY_BUFFER_SIZE);
+  int32_t bytes_read = 0;
+  int32_t index = 0;
+  int32_t buffer_length = std::min<int32_t>(COPY_BUFFER_SIZE, length);
+  while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) {
+    if (Put(index, &(b[0]), 0, bytes_read) != bytes_read) {
+#if defined (SFNTLY_NO_EXCEPTION)
+      return 0;
+#else
+      throw IOException("Error writing bytes.");
+#endif
+    }
+    index += bytes_read;
+    length -= bytes_read;
+    buffer_length = std::min<int32_t>(b.size(), length);
+  }
+  return true;
+}
+
+bool ByteArray::CopyFrom(InputStream* is) {
+  ByteVector b(COPY_BUFFER_SIZE);
+  int32_t bytes_read = 0;
+  int32_t index = 0;
+  int32_t buffer_length = COPY_BUFFER_SIZE;
+  while ((bytes_read = is->Read(&b, 0, buffer_length)) > 0) {
+    if (Put(index, &b[0], 0, bytes_read) != bytes_read) {
+#if defined (SFNTLY_NO_EXCEPTION)
+      return 0;
+#else
+      throw IOException("Error writing bytes.");
+#endif
+    }
+    index += bytes_read;
+  }
+  return true;
+}
+
+ByteArray::ByteArray(int32_t filled_length,
+                     int32_t storage_length,
+                     bool growable) {
+  Init(filled_length, storage_length, growable);
+}
+
+ByteArray::ByteArray(int32_t filled_length, int32_t storage_length) {
+  Init(filled_length, storage_length, false);
+}
+
+void ByteArray::Init(int32_t filled_length,
+                     int32_t storage_length,
+                     bool growable) {
+  storage_length_ = storage_length;
+  growable_ = growable;
+  SetFilledLength(filled_length);
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/data/byte_array.h b/cpp/src/sfntly/data/byte_array.h
new file mode 100644
index 0000000..70dc92f
--- /dev/null
+++ b/cpp/src/sfntly/data/byte_array.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011 The sfntly Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/input_stream.h"
+#include "sfntly/port/output_stream.h"
+
+namespace sfntly {
+
+// An abstraction to a contiguous array of bytes.
+// C++ port of this class assumes that the data are stored in a linear region
+// like std::vector.
+class ByteArray : virtual public RefCount {
+ public:
+  virtual ~ByteArray();
+
+  // Gets the current filled and readable length of the array.
+  int32_t Length();
+
+  // Gets the maximum size of the array. This is the maximum number of bytes that
+  // the array can hold and all of it may not be filled with data or even fully
+  // allocated yet.
+  int32_t Size();
+
+  // Determines whether or not this array is growable or of fixed size.
+  bool growable() { return growable_; }
+
+  int32_t SetFilledLength(int32_t filled_length);
+
+  // Gets the byte from the given index.
+  // @param index the index into the byte array
+  // @return the byte or -1 if reading beyond the bounds of the data
+  virtual int32_t Get(int32_t index);
+
+  // Gets the bytes from the given index and fill the buffer with them. As many
+  // bytes as will fit into the buffer are read unless that would go past the
+  // end of the array.
+  // @param index the index into the byte array
+  // @param b the buffer to put the bytes read into
+  // @return the number of bytes read from the buffer
+  virtual int32_t Get(int32_t index, ByteVector* b);
+
+  // Gets the bytes from the given index and fill the buffer with them starting
+  // at the offset given. As many bytes as the specified length are read unless
+  // that would go past the end of the array.
+  // @param index the index into the byte array
+  // @param b the buffer to put the bytes read into
+  // @param offset the location in the buffer to start putting the bytes
+  // @param length the number of bytes to put into the buffer
+  // @return the number of bytes read from the buffer
+  virtual int32_t Get(int32_t index,
+                      byte_t* b,
+                      int32_t offset,
+                      int32_t length);
+
+  // Puts the specified byte into the array at the given index unless that would
+  // be beyond the length of the array and it isn't growable.
+  virtual void Put(int32_t index, byte_t b);
+
+  // Puts the specified bytes into the array at the given index. The entire
+  // buffer is put into the array unless that would extend beyond the length and
+  // the array isn't growable.
+  virtual int32_t Put(int32_t index, ByteVector* b);
+
+  // Puts the specified bytes into the array at the given index. All of the bytes
+  // specified are put into the array unless that would extend beyond the length
+  // and the array isn't growable. The bytes to be put into the array are those
+  // in the buffer from the given offset and for the given length.
+  // @param index the index into the ByteArray
+  // @param b the bytes to put into the array
+  // @param offset the offset in the bytes to start copying from
+  // @param length the number of bytes to copy into the array
+  // @return the number of bytes actually written
+  virtual int32_t Put(int32_t index,
+                      byte_t* b,
+                      int32_t offset,
+                      int32_t length);
+
+  // Fully copies this ByteArray to another ByteArray to the extent that the
+  // destination array has storage for the data copied.
+  virtual int32_t CopyTo(ByteArray* array);
+
+  // Copies a segment of this ByteArray to another ByteArray.
+  // @param array the destination
+  // @param offset the offset in this ByteArray to start copying from
+  // @param length the maximum length in bytes to copy
+  // @return the number of bytes copied
+  virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length);
+
+  // Copies this ByteArray to another ByteArray.
+  // @param dstOffset the offset in the destination array to start copying to
+  // @param array the destination
+  // @param srcOffset the offset in this ByteArray to start copying from
+  // @param length the maximum length in bytes to copy
+  // @return the number of bytes copied
+  virtual int32_t CopyTo(int32_t dst_offset,
+                         ByteArray* array,
+                         int32_t src_offset,
+                         int32_t length);
+
+  // Copies this ByteArray to an OutputStream.
+  // @param os the destination
+  // @return the number of bytes copied
+  virtual int32_t CopyTo(OutputStream* os);
+
+  // Copies this ByteArray to an OutputStream.
+  // @param os the destination
+  // @param offset
+  // @param length
+  // @return the number of bytes copied
+  virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length);
+
+  // Copies from the InputStream into this ByteArray.
+  // @param is the source
+  // @param length the number of bytes to copy
+  virtual bool CopyFrom(InputStream* is, int32_t length);
+
+  // Copies everything from the InputStream into this ByteArray.
+  // @param is the source
+  virtual bool CopyFrom(InputStream* is);
+
+ protected:
+  // filledLength the length that is "filled" and readable counting from offset.
+  // storageLength the maximum storage size of the underlying data.
+  // growable is the storage growable - storageLength is the max growable size.
+  ByteArray(int32_t filled_length, int32_t storage_length, bool growable);
+  ByteArray(int32_t filled_length, int32_t storage_length);
+  void Init(int32_t filled_length, int32_t storage_length, bool growable);
+
+  // Internal subclass API
+
+  // Stores the byte at the index given.
+  // @param index the location to store at
+  // @param b the byte to store
+  virtual void InternalPut(int32_t index, byte_t b) = 0;
+
+  // Stores the array of bytes at the given index.
+  // @param index the location to store at
+  // @param b the bytes to store
+  // @param offset the offset to start from in the byte array
+  // @param length the length of the byte array to store from the offset
+  // @return the number of bytes actually stored
+  virtual int32_t InternalPut(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length) = 0;
+
+  // Gets the byte at the index given.
+  // @param index the location to get from
+  // @return the byte stored at the index
+  virtual byte_t InternalGet(int32_t index) = 0;
+
+  // Gets the bytes at the index given of the given length.
+  // @param index the location to start getting from
+  // @param b the array to put the bytes into
+  // @param offset the offset in the array to put the bytes into
+  // @param length the length of bytes to read
+  // @return the number of bytes actually ready
+  virtual int32_t InternalGet(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length) = 0;
+
+  // Close this instance of the ByteArray.
+  virtual void Close() = 0;
+
+  // C++ port only, raw pointer to the first element of storage.
+  virtual byte_t* Begin() = 0;
+
+  // Java toString() not ported.
+
+  static const int32_t COPY_BUFFER_SIZE;
+
+ private:
+  //bool bound_;  // unused, comment out
+  int32_t filled_length_;
+  int32_t storage_length_;
+  bool growable_;
+};
+typedef Ptr<ByteArray> ByteArrayPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_BYTE_ARRAY_H_
diff --git a/cpp/src/sfntly/data/font_data.cc b/cpp/src/sfntly/data/font_data.cc
new file mode 100644
index 0000000..d2b95ea
--- /dev/null
+++ b/cpp/src/sfntly/data/font_data.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <limits.h>
+#include <algorithm>
+#include <functional>
+
+#include "sfntly/data/font_data.h"
+
+namespace sfntly {
+
+int32_t FontData::Size() const {
+  return std::min<int32_t>(array_->Size() - bound_offset_, bound_length_);
+}
+
+bool FontData::Bound(int32_t offset, int32_t length) {
+  if (offset + length > Size() || offset < 0 || length < 0)
+    return false;
+
+  bound_offset_ += offset;
+  bound_length_ = length;
+  return true;
+}
+
+bool FontData::Bound(int32_t offset) {
+if (offset > Size() || offset < 0)
+    return false;
+
+  bound_offset_ += offset;
+  return true;
+}
+
+int32_t FontData::Length() const {
+  return std::min<int32_t>(array_->Length() - bound_offset_, bound_length_);
+}
+
+FontData::FontData(ByteArray* ba) {
+  Init(ba);
+}
+
+FontData::FontData(FontData* data, int32_t offset, int32_t length) {
+  Init(data->array_);
+  Bound(data->bound_offset_ + offset, length);
+}
+
+FontData::FontData(FontData* data, int32_t offset) {
+  Init(data->array_);
+  Bound(data->bound_offset_ + offset,
+        (data->bound_length_ == GROWABLE_SIZE)
+            ? GROWABLE_SIZE : data->bound_length_ - offset);
+}
+
+FontData::~FontData() {}
+
+void FontData::Init(ByteArray* ba) {
+  array_ = ba;
+  bound_offset_ = 0;
+  bound_length_ = GROWABLE_SIZE;
+}
+
+int32_t FontData::BoundOffset(int32_t offset) {
+  return offset + bound_offset_;
+}
+
+int32_t FontData::BoundLength(int32_t offset, int32_t length) {
+  return std::min<int32_t>(length, bound_length_ - offset);
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/data/font_data.h b/cpp/src/sfntly/data/font_data.h
new file mode 100644
index 0000000..d02e8b7
--- /dev/null
+++ b/cpp/src/sfntly/data/font_data.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_
+
+#include <limits.h>
+
+#include <vector>
+
+#include "sfntly/port/type.h"
+#include "sfntly/data/byte_array.h"
+#include "sfntly/port/refcount.h"
+
+namespace sfntly {
+
+struct DataSize {
+  enum {
+    kBYTE = 1,
+    kCHAR = 1,
+    kUSHORT = 2,
+    kSHORT = 2,
+    kUINT24 = 3,
+    kULONG = 4,
+    kLONG = 4,
+    kFixed = 4,
+    kFUNIT = 4,
+    kFWORD = 2,
+    kUFWORD = 2,
+    kF2DOT14 = 2,
+    kLONGDATETIME = 8,
+    kTag = 4,
+    kGlyphID = 2,
+    kOffset = 2
+  };
+};
+
+class FontData : virtual public RefCount {
+ public:
+  // Gets the maximum size of the FontData. This is the maximum number of bytes
+  // that the font data can hold and all of it may not be filled with data or
+  // even fully allocated yet.
+  // @return the maximum size of this font data
+  virtual int32_t Size() const;
+
+  // Sets limits on the size of the FontData. The FontData is then only
+  // visible within the bounds set.
+  // @param offset the start of the new bounds
+  // @param length the number of bytes in the bounded array
+  // @return true if the bounding range was successful; false otherwise
+  virtual bool Bound(int32_t offset, int32_t length);
+
+  // Sets limits on the size of the FontData. This is a offset bound only so if
+  // the FontData is writable and growable then there is no limit to that growth
+  // from the bounding operation.
+  // @param offset the start of the new bounds which must be within the current
+  //        size of the FontData
+  // @return true if the bounding range was successful; false otherwise
+  virtual bool Bound(int32_t offset);
+
+  // Makes a slice of this FontData. The returned slice will share the data with
+  // the original <code>FontData</code>.
+  // @param offset the start of the slice
+  // @param length the number of bytes in the slice
+  // @return a slice of the original FontData
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length) = 0;
+
+  // Makes a bottom bound only slice of this array. The returned slice will
+  // share the data with the original <code>FontData</code>.
+  // @param offset the start of the slice
+  // @return a slice of the original FontData
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset) = 0;
+
+  // Gets the length of the data.
+  virtual int32_t Length() const;
+
+ protected:
+  // Constructor.
+  // @param ba the byte array to use for the backing data
+  explicit FontData(ByteArray* ba);
+
+  // Constructor.
+  // @param data the data to wrap
+  // @param offset the offset to start the wrap from
+  // @param length the length of the data wrapped
+  FontData(FontData* data, int32_t offset, int32_t length);
+
+  // Constructor.
+  // @param data the data to wrap
+  // @param offset the offset to start the wrap from
+  FontData(FontData* data, int32_t offset);
+  virtual ~FontData();
+
+  void Init(ByteArray* ba);
+
+  // Gets the offset in the underlying data taking into account any bounds on
+  // the data.
+  // @param offset the offset to get the bound compensated offset for
+  // @return the bound compensated offset
+  int32_t BoundOffset(int32_t offset);
+
+  // Gets the length in the underlying data taking into account any bounds on
+  // the data.
+  // @param offset the offset that the length is being used at
+  // @param length the length to get the bound compensated length for
+  // @return the bound compensated length
+  int32_t BoundLength(int32_t offset, int32_t length);
+
+  static const int32_t GROWABLE_SIZE = INT_MAX;
+
+  // TODO(arthurhsu): style guide violation: refactor this protected member
+  ByteArrayPtr array_;
+
+ private:
+  int32_t bound_offset_;
+  int32_t bound_length_;
+};
+typedef Ptr<FontData> FontDataPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_DATA_H_
diff --git a/cpp/src/sfntly/data/font_input_stream.cc b/cpp/src/sfntly/data/font_input_stream.cc
new file mode 100644
index 0000000..dcf8be3
--- /dev/null
+++ b/cpp/src/sfntly/data/font_input_stream.cc
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/data/font_input_stream.h"
+
+#include <algorithm>
+
+namespace sfntly {
+
+FontInputStream::FontInputStream(InputStream* is)
+    : stream_(is), position_(0), length_(0), bounded_(false) {
+}
+
+FontInputStream::FontInputStream(InputStream* is, size_t length)
+    : stream_(is), position_(0), length_(length), bounded_(true) {
+}
+
+FontInputStream::~FontInputStream() {
+  // Do not close here, underlying InputStream will close themselves.
+}
+
+int32_t FontInputStream::Available() {
+  if (stream_) {
+    return stream_->Available();
+  }
+  return 0;
+}
+
+void FontInputStream::Close() {
+  if (stream_) {
+    stream_->Close();
+  }
+}
+
+void FontInputStream::Mark(int32_t readlimit) {
+  if (stream_) {
+    stream_->Mark(readlimit);
+  }
+}
+
+bool FontInputStream::MarkSupported() {
+  if (stream_) {
+    return stream_->MarkSupported();
+  }
+  return false;
+}
+
+void FontInputStream::Reset() {
+  if (stream_) {
+    stream_->Reset();
+  }
+}
+
+int32_t FontInputStream::Read() {
+  if (!stream_ || (bounded_ && position_ >= length_)) {
+    return -1;
+  }
+  int32_t b = stream_->Read();
+  if (b >= 0) {
+    position_++;
+  }
+  return b;
+}
+
+int32_t FontInputStream::Read(ByteVector* b, int32_t offset, int32_t length) {
+  if (!stream_ || offset < 0 || length < 0 ||
+      (bounded_ && position_ >= length_)) {
+    return -1;
+  }
+  int32_t bytes_to_read =
+      bounded_ ? std::min<int32_t>(length, (int32_t)(length_ - position_)) :
+                 length;
+  int32_t bytes_read = stream_->Read(b, offset, bytes_to_read);
+  position_ += bytes_read;
+  return bytes_read;
+}
+
+int32_t FontInputStream::Read(ByteVector* b) {
+  return Read(b, 0, b->size());
+}
+
+int32_t FontInputStream::ReadChar() {
+  return Read();
+}
+
+int32_t FontInputStream::ReadUShort() {
+  return 0xffff & (Read() << 8 | Read());
+}
+
+int32_t FontInputStream::ReadShort() {
+  return ((Read() << 8 | Read()) << 16) >> 16;
+}
+
+int32_t FontInputStream::ReadUInt24() {
+  return 0xffffff & (Read() << 16 | Read() << 8 | Read());
+}
+
+int64_t FontInputStream::ReadULong() {
+  return 0xffffffffL & ReadLong();
+}
+
+int32_t FontInputStream::ReadULongAsInt() {
+  int64_t ulong = ReadULong();
+  return ((int32_t)ulong) & ~0x80000000;
+}
+
+int32_t FontInputStream::ReadLong() {
+  return Read() << 24 | Read() << 16 | Read() << 8 | Read();
+}
+
+int32_t FontInputStream::ReadFixed() {
+  return ReadLong();
+}
+
+int64_t FontInputStream::ReadDateTimeAsLong() {
+  return (int64_t)ReadULong() << 32 | ReadULong();
+}
+
+int64_t FontInputStream::Skip(int64_t n) {
+  if (stream_) {
+    int64_t skipped = stream_->Skip(n);
+    position_ += skipped;
+    return skipped;
+  }
+  return 0;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/data/font_input_stream.h b/cpp/src/sfntly/data/font_input_stream.h
new file mode 100644
index 0000000..9992b07
--- /dev/null
+++ b/cpp/src/sfntly/data/font_input_stream.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_
+
+#include "sfntly/port/type.h"
+#include "sfntly/port/input_stream.h"
+
+namespace sfntly {
+
+// An input stream for reading font data.
+// The data types used are as listed:
+// BYTE       8-bit unsigned integer.
+// CHAR       8-bit signed integer.
+// USHORT     16-bit unsigned integer.
+// SHORT      16-bit signed integer.
+// UINT24     24-bit unsigned integer.
+// ULONG      32-bit unsigned integer.
+// LONG       32-bit signed integer.
+// Fixed      32-bit signed fixed-point number (16.16)
+// FUNIT      Smallest measurable distance in the em space.
+// FWORD      16-bit signed integer (SHORT) that describes a quantity in FUnits.
+// UFWORD     16-bit unsigned integer (USHORT) that describes a quantity in
+//            FUnits.
+// F2DOT14    16-bit signed fixed number with the low 14 bits of fraction (2.14)
+// LONGDATETIME  Date represented in number of seconds since 12:00 midnight,
+//               January 1, 1904. The value is represented as a signed 64-bit
+//               integer.
+
+// Note: Original class inherits from Java's FilterOutputStream, which wraps
+//       an InputStream within.  In C++, we directly do the wrapping without
+//       defining another layer of abstraction.  The wrapped output stream is
+//       *NOT* reference counted (because it's meaningless to ref-count an I/O
+//       stream).
+class FontInputStream : public InputStream {
+ public:
+  // Constructor.
+  // @param is input stream to wrap
+  explicit FontInputStream(InputStream* is);
+
+  // Constructor for a bounded font input stream.
+  // @param is input stream to wrap
+  // @param length the maximum length of bytes to read
+  FontInputStream(InputStream* is, size_t length);
+
+  virtual ~FontInputStream();
+
+
+  virtual int32_t Available();
+  virtual void Close();
+  virtual void Mark(int32_t readlimit);
+  virtual bool MarkSupported();
+  virtual void Reset();
+
+  virtual int32_t Read();
+  virtual int32_t Read(ByteVector* buffer);
+  virtual int32_t Read(ByteVector* buffer, int32_t offset, int32_t length);
+
+  // Get the current position in the stream in bytes.
+  // @return the current position in bytes
+  virtual int64_t position() { return position_; }
+
+  virtual int32_t ReadChar();
+  virtual int32_t ReadUShort();
+  virtual int32_t ReadShort();
+  virtual int32_t ReadUInt24();
+  virtual int64_t ReadULong();
+  virtual int32_t ReadULongAsInt();
+  virtual int32_t ReadLong();
+  virtual int32_t ReadFixed();
+  virtual int64_t ReadDateTimeAsLong();
+  virtual int64_t Skip(int64_t n);  // n can be negative.
+
+ private:
+  InputStream* stream_;
+  int64_t position_;
+  int64_t length_;  // Bound on length of data to read.
+  bool bounded_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_INPUT_STREAM_H_
diff --git a/cpp/src/sfntly/data/font_output_stream.cc b/cpp/src/sfntly/data/font_output_stream.cc
new file mode 100644
index 0000000..3422a22
--- /dev/null
+++ b/cpp/src/sfntly/data/font_output_stream.cc
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/data/font_output_stream.h"
+
+#include <algorithm>
+
+namespace sfntly {
+
+FontOutputStream::FontOutputStream(OutputStream* os)
+    : stream_(os),
+      position_(0) {
+}
+
+FontOutputStream::~FontOutputStream() {
+  // Do not close, underlying stream shall clean up themselves.
+}
+
+void FontOutputStream::Write(byte_t b) {
+  if (stream_) {
+    stream_->Write(b);
+    position_++;
+  }
+}
+
+void FontOutputStream::Write(ByteVector* b) {
+  if (b) {
+    Write(b, 0, b->size());
+    position_ += b->size();
+  }
+}
+
+void FontOutputStream::Write(ByteVector* b, int32_t off, int32_t len) {
+  assert(b);
+  assert(stream_);
+  if (off < 0 || len < 0 || off + len < 0 ||
+      static_cast<size_t>(off + len) > b->size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#else
+    return;
+#endif
+  }
+
+  stream_->Write(b, off, len);
+  position_ += len;
+}
+
+void FontOutputStream::Write(byte_t* b, int32_t off, int32_t len) {
+  assert(b);
+  assert(stream_);
+  if (off < 0 || len < 0 || off + len < 0) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#else
+    return;
+#endif
+  }
+
+  stream_->Write(b, off, len);
+  position_ += len;
+}
+
+void FontOutputStream::WriteChar(byte_t c) {
+  Write(c);
+}
+
+void FontOutputStream::WriteUShort(int32_t us) {
+  Write((byte_t)((us >> 8) & 0xff));
+  Write((byte_t)(us & 0xff));
+}
+
+void FontOutputStream::WriteShort(int32_t s) {
+  WriteUShort(s);
+}
+
+void FontOutputStream::WriteUInt24(int32_t ui) {
+  Write((byte_t)(ui >> 16) & 0xff);
+  Write((byte_t)(ui >> 8) & 0xff);
+  Write((byte_t)ui & 0xff);
+}
+
+void FontOutputStream::WriteULong(int64_t ul) {
+  Write((byte_t)((ul >> 24) & 0xff));
+  Write((byte_t)((ul >> 16) & 0xff));
+  Write((byte_t)((ul >> 8) & 0xff));
+  Write((byte_t)(ul & 0xff));
+}
+
+void FontOutputStream::WriteLong(int64_t l) {
+  WriteULong(l);
+}
+
+void FontOutputStream::WriteFixed(int32_t f) {
+  WriteULong(f);
+}
+
+void FontOutputStream::WriteDateTime(int64_t date) {
+  WriteULong((date >> 32) & 0xffffffff);
+  WriteULong(date & 0xffffffff);
+}
+
+void FontOutputStream::Flush() {
+  if (stream_) {
+    stream_->Flush();
+  }
+}
+
+void FontOutputStream::Close() {
+  if (stream_) {
+    stream_->Flush();
+    stream_->Close();
+    position_ = 0;
+  }
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/data/font_output_stream.h b/cpp/src/sfntly/data/font_output_stream.h
new file mode 100644
index 0000000..fcd48e8
--- /dev/null
+++ b/cpp/src/sfntly/data/font_output_stream.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_
+
+#include "sfntly/port/type.h"
+#include "sfntly/port/output_stream.h"
+
+namespace sfntly {
+
+// An output stream for writing font data.
+// The data types used are as listed:
+// BYTE       8-bit unsigned integer.
+// CHAR       8-bit signed integer.
+// USHORT     16-bit unsigned integer.
+// SHORT      16-bit signed integer.
+// UINT24     24-bit unsigned integer.
+// ULONG      32-bit unsigned integer.
+// LONG       32-bit signed integer.
+// Fixed      32-bit signed fixed-point number (16.16)
+// FUNIT      Smallest measurable distance in the em space.
+// FWORD      16-bit signed integer (SHORT) that describes a quantity in FUnits.
+// UFWORD     16-bit unsigned integer (USHORT) that describes a quantity in
+//            FUnits.
+// F2DOT14    16-bit signed fixed number with the low 14 bits of fraction (2.14)
+// LONGDATETIME  Date represented in number of seconds since 12:00 midnight,
+//               January 1, 1904. The value is represented as a signed 64-bit
+//               integer.
+
+// Note: The wrapped output stream is *NOT* reference counted (because it's
+//       meaningless to ref-count an I/O stream).
+class FontOutputStream : public OutputStream {
+ public:
+  explicit FontOutputStream(OutputStream* os);
+  virtual ~FontOutputStream();
+
+  virtual size_t position() { return position_; }
+
+  virtual void Write(byte_t b);
+  virtual void Write(ByteVector* b);
+  virtual void Write(ByteVector* b, int32_t off, int32_t len);
+  virtual void Write(byte_t* b, int32_t off, int32_t len);
+  virtual void WriteChar(byte_t c);
+  virtual void WriteUShort(int32_t us);
+  virtual void WriteShort(int32_t s);
+  virtual void WriteUInt24(int32_t ui);
+  virtual void WriteULong(int64_t ul);
+  virtual void WriteLong(int64_t l);
+  virtual void WriteFixed(int32_t l);
+  virtual void WriteDateTime(int64_t date);
+
+  // Note: C++ port only.
+  virtual void Flush();
+  virtual void Close();
+
+ private:
+  // Note: we do not use the variable name out as in Java because it has
+  //       special meaning in VC++ and will be very confusing.
+  OutputStream* stream_;
+  size_t position_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_FONT_OUTPUT_STREAM_H_
diff --git a/cpp/src/sfntly/data/growable_memory_byte_array.cc b/cpp/src/sfntly/data/growable_memory_byte_array.cc
new file mode 100644
index 0000000..c335614
--- /dev/null
+++ b/cpp/src/sfntly/data/growable_memory_byte_array.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/data/growable_memory_byte_array.h"
+
+#include <limits.h>
+#include <string.h>
+
+#include <algorithm>
+
+namespace sfntly {
+
+GrowableMemoryByteArray::GrowableMemoryByteArray()
+    : ByteArray(0, INT_MAX, true) {
+  // Note: We did not set an initial size of array like Java because STL
+  //       implementation will determine the best strategy.
+}
+
+GrowableMemoryByteArray::~GrowableMemoryByteArray() {}
+
+int32_t GrowableMemoryByteArray::CopyTo(OutputStream* os,
+                                        int32_t offset,
+                                        int32_t length) {
+  assert(os);
+  os->Write(&b_, offset, length);
+  return length;
+}
+
+void GrowableMemoryByteArray::InternalPut(int32_t index, byte_t b) {
+  if ((size_t)index >= b_.size()) {
+    b_.resize((size_t)(index + 1));
+  }
+  b_[index] = b;
+}
+
+int32_t GrowableMemoryByteArray::InternalPut(int32_t index,
+                                             byte_t* b,
+                                             int32_t offset,
+                                             int32_t length) {
+  if ((size_t)index + length >= b_.size()) {
+    // Note: We grow one byte more than Java version. VC debuggers shows
+    //       data better this way.
+    b_.resize((size_t)(index + length + 1));
+  }
+  std::copy(b + offset, b + offset + length, b_.begin() + index);
+  return length;
+}
+
+byte_t GrowableMemoryByteArray::InternalGet(int32_t index) {
+  return b_[index];
+}
+
+int32_t GrowableMemoryByteArray::InternalGet(int32_t index,
+                                             byte_t* b,
+                                             int32_t offset,
+                                             int32_t length) {
+  memcpy(b + offset, &(b_[0]) + index, length);
+  return length;
+}
+
+void GrowableMemoryByteArray::Close() {
+  b_.clear();
+}
+
+byte_t* GrowableMemoryByteArray::Begin() {
+  return &(b_[0]);
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/data/growable_memory_byte_array.h b/cpp/src/sfntly/data/growable_memory_byte_array.h
new file mode 100644
index 0000000..8583a0d
--- /dev/null
+++ b/cpp/src/sfntly/data/growable_memory_byte_array.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_
+
+#include "sfntly/data/byte_array.h"
+
+namespace sfntly {
+
+// Note: This is not really a port of Java version. Instead, this wraps a
+//       std::vector inside and let it grow by calling resize().
+class GrowableMemoryByteArray : public ByteArray,
+                                public RefCounted<GrowableMemoryByteArray> {
+ public:
+  GrowableMemoryByteArray();
+  virtual ~GrowableMemoryByteArray();
+  virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length);
+
+  // Make gcc -Woverloaded-virtual happy.
+  virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); }
+  virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) {
+    return ByteArray::CopyTo(array, offset, length);
+  }
+  virtual int32_t CopyTo(int32_t dst_offset,
+                         ByteArray* array,
+                         int32_t src_offset,
+                         int32_t length) {
+    return ByteArray::CopyTo(dst_offset, array, src_offset, length);
+  }
+  virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); }
+
+ protected:
+  virtual void InternalPut(int32_t index, byte_t b);
+  virtual int32_t InternalPut(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length);
+  virtual byte_t InternalGet(int32_t index);
+  virtual int32_t InternalGet(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length);
+  virtual void Close();
+  virtual byte_t* Begin();
+
+ private:
+  ByteVector b_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_GROWABLE_MEMORY_BYTE_ARRAY_H_
diff --git a/cpp/src/sfntly/data/memory_byte_array.cc b/cpp/src/sfntly/data/memory_byte_array.cc
new file mode 100644
index 0000000..d6c9c48
--- /dev/null
+++ b/cpp/src/sfntly/data/memory_byte_array.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/data/memory_byte_array.h"
+
+#include <string.h>
+
+namespace sfntly {
+
+MemoryByteArray::MemoryByteArray(int32_t length)
+    : ByteArray(0, length), b_(NULL), allocated_(true) {
+}
+
+MemoryByteArray::MemoryByteArray(byte_t* b, int32_t filled_length)
+    : ByteArray(filled_length, filled_length), b_(b), allocated_(false) {
+  assert(b);
+}
+
+MemoryByteArray::~MemoryByteArray() {
+  Close();
+}
+
+int32_t MemoryByteArray::CopyTo(OutputStream* os,
+                                int32_t offset,
+                                int32_t length) {
+  assert(os);
+  os->Write(b_, offset, length);
+  return length;
+}
+
+void MemoryByteArray::Init() {
+  if (allocated_ && b_ == NULL) {
+    b_ = new byte_t[Size()];
+    memset(b_, 0, Size());
+  }
+}
+
+void MemoryByteArray::InternalPut(int32_t index, byte_t b) {
+  Init();
+  b_[index] = b;
+}
+
+int32_t MemoryByteArray::InternalPut(int32_t index,
+                                     byte_t* b,
+                                     int32_t offset,
+                                     int32_t length) {
+  assert(b);
+  Init();
+  memcpy(b_ + index, b + offset, length);
+  return length;
+}
+
+byte_t MemoryByteArray::InternalGet(int32_t index) {
+  Init();
+  return b_[index];
+}
+
+int32_t MemoryByteArray::InternalGet(int32_t index,
+                                     byte_t* b,
+                                     int32_t offset,
+                                     int32_t length) {
+  assert(b);
+  Init();
+  memcpy(b + offset, b_ + index, length);
+  return length;
+}
+
+void MemoryByteArray::Close() {
+  if (allocated_ && b_) {
+    delete[] b_;
+  }
+  b_ = NULL;
+}
+
+byte_t* MemoryByteArray::Begin() {
+  Init();
+  return b_;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/data/memory_byte_array.h b/cpp/src/sfntly/data/memory_byte_array.h
new file mode 100644
index 0000000..838fd1a
--- /dev/null
+++ b/cpp/src/sfntly/data/memory_byte_array.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_
+
+#include "sfntly/data/byte_array.h"
+
+namespace sfntly {
+
+class MemoryByteArray : public ByteArray, public RefCounted<MemoryByteArray> {
+ public:
+  // Construct a new MemoryByteArray with a new array of the size given. It is
+  // assumed that none of the array is filled and readable.
+  explicit MemoryByteArray(int32_t length);
+
+  // Note: not implemented due to dangerous operations in constructor.
+  //explicit MemoryByteArray(ByteVector* b);
+
+  // Construct a new MemoryByteArray using byte array.
+  // @param b the byte array that provides the actual storage
+  // @param filled_length the index of the last byte in the array has data
+  // Note: This is different from Java version, it does not take over the
+  //       ownership of b.  Caller is responsible for handling the lifetime
+  //       of b.  C++ port also assumes filled_length is buffer_length since
+  //       there is not a reliable way to identify the actual size of buffer.
+  MemoryByteArray(byte_t* b, int32_t filled_length);
+
+  virtual ~MemoryByteArray();
+  virtual int32_t CopyTo(OutputStream* os, int32_t offset, int32_t length);
+
+  // Make gcc -Woverloaded-virtual happy.
+  virtual int32_t CopyTo(ByteArray* array) { return ByteArray::CopyTo(array); }
+  virtual int32_t CopyTo(ByteArray* array, int32_t offset, int32_t length) {
+    return ByteArray::CopyTo(array, offset, length);
+  }
+  virtual int32_t CopyTo(int32_t dst_offset,
+                         ByteArray* array,
+                         int32_t src_offset,
+                         int32_t length) {
+    return ByteArray::CopyTo(dst_offset, array, src_offset, length);
+  }
+  virtual int32_t CopyTo(OutputStream* os) { return ByteArray::CopyTo(os); }
+
+ protected:
+  virtual void InternalPut(int32_t index, byte_t b);
+  virtual int32_t InternalPut(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length);
+  virtual byte_t InternalGet(int32_t index);
+  virtual int32_t InternalGet(int32_t index,
+                              byte_t* b,
+                              int32_t offset,
+                              int32_t length);
+  virtual void Close();
+  virtual byte_t* Begin();
+
+ private:
+  void Init();  // C++ port only, used to allocate memory outside constructor.
+
+  byte_t* b_;
+  bool allocated_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_MEMORY_BYTE_ARRAY_H_
diff --git a/cpp/src/sfntly/data/readable_font_data.cc b/cpp/src/sfntly/data/readable_font_data.cc
new file mode 100644
index 0000000..06d783f
--- /dev/null
+++ b/cpp/src/sfntly/data/readable_font_data.cc
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/data/readable_font_data.h"
+
+#include <stdio.h>
+
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/data/writable_font_data.h"
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+
+ReadableFontData::ReadableFontData(ByteArray* array)
+    : FontData(array),
+      checksum_set_(false),
+      checksum_(0) {
+}
+
+ReadableFontData::~ReadableFontData() {}
+
+// TODO(arthurhsu): re-investigate the memory model of this function.  It's
+//                  not too useful without copying, but it's not performance
+//                  savvy to do copying.
+CALLER_ATTACH
+ReadableFontData* ReadableFontData::CreateReadableFontData(ByteVector* b) {
+  assert(b);
+  ByteArrayPtr ba = new MemoryByteArray(b->size());
+  ba->Put(0, b);
+  ReadableFontDataPtr wfd = new ReadableFontData(ba);
+  return wfd.Detach();
+}
+
+int64_t ReadableFontData::Checksum() {
+  AutoLock lock(checksum_lock_);
+  if (!checksum_set_) {
+    ComputeChecksum();
+  }
+  return checksum_;
+}
+
+void ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) {
+  checksum_range_ = ranges;
+  checksum_set_ = false;  // UNIMPLEMENTED: atomicity
+}
+
+int32_t ReadableFontData::ReadUByte(int32_t index) {
+  int32_t b = array_->Get(BoundOffset(index));
+#if !defined (SFNTLY_NO_EXCEPTION)
+  if (b < 0) {
+    throw IndexOutOfBoundException(
+        "Index attempted to be read from is out of bounds", index);
+  }
+#endif
+  return b;
+}
+
+int32_t ReadableFontData::ReadByte(int32_t index) {
+  int32_t b = array_->Get(BoundOffset(index));
+#if !defined (SFNTLY_NO_EXCEPTION)
+  if (b < 0) {
+    throw IndexOutOfBoundException(
+        "Index attempted to be read from is out of bounds", index);
+  }
+#endif
+  return (b << 24) >> 24;
+}
+
+int32_t ReadableFontData::ReadBytes(int32_t index,
+                                    byte_t* b,
+                                    int32_t offset,
+                                    int32_t length) {
+  return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length));
+}
+
+int32_t ReadableFontData::ReadChar(int32_t index) {
+  return ReadUByte(index);
+}
+
+int32_t ReadableFontData::ReadUShort(int32_t index) {
+  return 0xffff & (ReadUByte(index) << 8 | ReadUByte(index + 1));
+}
+
+int32_t ReadableFontData::ReadShort(int32_t index) {
+  return ((ReadByte(index) << 8 | ReadUByte(index + 1)) << 16) >> 16;
+}
+
+int32_t ReadableFontData::ReadUInt24(int32_t index) {
+  return 0xffffff & (ReadUByte(index) << 16 |
+                     ReadUByte(index + 1) << 8 |
+                     ReadUByte(index + 2));
+}
+
+int64_t ReadableFontData::ReadULong(int32_t index) {
+  return 0xffffffffL & (ReadUByte(index) << 24 |
+                        ReadUByte(index + 1) << 16 |
+                        ReadUByte(index + 2) << 8 |
+                        ReadUByte(index + 3));
+}
+
+int32_t ReadableFontData::ReadULongAsInt(int32_t index) {
+  int64_t ulong = ReadULong(index);
+#if !defined (SFNTLY_NO_EXCEPTION)
+  if ((ulong & 0x80000000) == 0x80000000) {
+    throw ArithmeticException("Long value too large to fit into an integer.");
+  }
+#endif
+  return static_cast<int32_t>(ulong);
+}
+
+int64_t ReadableFontData::ReadULongLE(int32_t index) {
+  return 0xffffffffL & (ReadUByte(index) |
+                        ReadUByte(index + 1) << 8 |
+                        ReadUByte(index + 2) << 16 |
+                        ReadUByte(index + 3) << 24);
+}
+
+int32_t ReadableFontData::ReadLong(int32_t index) {
+  return ReadByte(index) << 24 |
+         ReadUByte(index + 1) << 16 |
+         ReadUByte(index + 2) << 8 |
+         ReadUByte(index + 3);
+}
+
+int32_t ReadableFontData::ReadFixed(int32_t index) {
+  return ReadLong(index);
+}
+
+int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) {
+  return (int64_t)ReadULong(index) << 32 | ReadULong(index + 4);
+}
+
+int32_t ReadableFontData::ReadFWord(int32_t index) {
+  return ReadShort(index);
+}
+
+int32_t ReadableFontData::ReadFUFWord(int32_t index) {
+  return ReadUShort(index);
+}
+
+int32_t ReadableFontData::CopyTo(OutputStream* os) {
+  return array_->CopyTo(os, BoundOffset(0), Length());
+}
+
+int32_t ReadableFontData::CopyTo(WritableFontData* wfd) {
+  return array_->CopyTo(wfd->BoundOffset(0),
+                        wfd->array_,
+                        BoundOffset(0),
+                        Length());
+}
+
+int32_t ReadableFontData::CopyTo(ByteArray* ba) {
+  return array_->CopyTo(ba, BoundOffset(0), Length());
+}
+
+int32_t ReadableFontData::SearchUShort(int32_t start_index,
+                                       int32_t start_offset,
+                                       int32_t end_index,
+                                       int32_t end_offset,
+                                       int32_t length,
+                                       int32_t key) {
+  int32_t location = 0;
+  int32_t bottom = 0;
+  int32_t top = length;
+  while (top != bottom) {
+    location = (top + bottom) / 2;
+    int32_t location_start = ReadUShort(start_index + location * start_offset);
+    if (key < location_start) {
+      // location is below current location
+      top = location;
+    } else {
+      // is key below the upper bound?
+      int32_t location_end = ReadUShort(end_index + location * end_offset);
+#if defined (SFNTLY_DEBUG_FONTDATA)
+      fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
+#endif
+      if (key <= location_end) {
+        return location;
+      } else {
+        // location is above the current location
+        bottom = location + 1;
+      }
+    }
+  }
+  return -1;
+}
+
+int32_t ReadableFontData::SearchUShort(int32_t start_index,
+                                       int32_t start_offset,
+                                       int32_t length,
+                                       int32_t key) {
+  int32_t location = 0;
+  int32_t bottom = 0;
+  int32_t top = length;
+  while (top != bottom) {
+    location = (top + bottom) / 2;
+    int32_t location_start = ReadUShort(start_index + location * start_offset);
+    if (key < location_start) {
+      // location is below current location
+      top = location;
+    } else if (key > location_start) {
+      // location is above current location
+      bottom = location + 1;
+    } else {
+      return location;
+    }
+  }
+  return -1;
+}
+
+int32_t ReadableFontData::SearchULong(int32_t start_index,
+                                      int32_t start_offset,
+                                      int32_t end_index,
+                                      int32_t end_offset,
+                                      int32_t length,
+                                      int32_t key) {
+  int32_t location = 0;
+  int32_t bottom = 0;
+  int32_t top = length;
+  while (top != bottom) {
+    location = (top + bottom) / 2;
+    int32_t location_start = ReadULongAsInt(start_index
+                                            + location * start_offset);
+    if (key < location_start) {
+      // location is below current location
+      top = location;
+    } else {
+      // is key below the upper bound?
+      int32_t location_end = ReadULongAsInt(end_index + location * end_offset);
+#if defined (SFNTLY_DEBUG_FONTDATA)
+      fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
+#endif
+      if (key <= location_end) {
+        return location;
+      } else {
+        // location is above the current location
+        bottom = location + 1;
+      }
+    }
+  }
+  return -1;
+}
+
+CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset,
+                                                int32_t length) {
+  if (offset < 0 || offset + length > Size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException(
+        "Attempt to bind data outside of its limits");
+#endif
+    return NULL;
+  }
+  FontDataPtr slice = new ReadableFontData(this, offset, length);
+  return slice.Detach();
+}
+
+CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) {
+  if (offset < 0 || offset > Size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException(
+        "Attempt to bind data outside of its limits");
+#endif
+    return NULL;
+  }
+  FontDataPtr slice = new ReadableFontData(this, offset);
+  return slice.Detach();
+}
+
+ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset)
+    : FontData(data, offset),
+      checksum_set_(false),
+      checksum_(0) {
+}
+
+ReadableFontData::ReadableFontData(ReadableFontData* data,
+                                   int32_t offset,
+                                   int32_t length)
+    : FontData(data, offset, length),
+      checksum_set_(false),
+      checksum_(0) {
+}
+
+void ReadableFontData::ComputeChecksum() {
+  // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity
+  int64_t sum = 0;
+  if (checksum_range_.empty()) {
+    sum = ComputeCheckSum(0, Length());
+  } else {
+    for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size();
+         low_bound_index += 2) {
+      int32_t low_bound = checksum_range_[low_bound_index];
+      int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ?
+                                Length() :
+                                checksum_range_[low_bound_index + 1];
+      sum += ComputeCheckSum(low_bound, high_bound);
+    }
+  }
+
+  checksum_ = sum & 0xffffffffL;
+  checksum_set_ = true;
+}
+
+int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound,
+                                          int32_t high_bound) {
+  int64_t sum = 0;
+  // Checksum all whole 4-byte chunks.
+  for (int32_t i = low_bound; i <= high_bound - 4; i += 4) {
+    sum += ReadULong(i);
+  }
+
+  // Add last fragment if not 4-byte multiple
+  int32_t off = high_bound & -4;
+  if (off < high_bound) {
+    int32_t b3 = ReadUByte(off);
+    int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0;
+    int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0;
+    int32_t b0 = 0;
+    sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
+  }
+  return sum;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/data/readable_font_data.h b/cpp/src/sfntly/data/readable_font_data.h
new file mode 100644
index 0000000..b43c626
--- /dev/null
+++ b/cpp/src/sfntly/data/readable_font_data.h
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_
+
+#include "sfntly/data/font_data.h"
+#include "sfntly/port/lock.h"
+
+namespace sfntly {
+
+class WritableFontData;
+class OutputStream;
+
+// Writable font data wrapper. Supports reading of data primitives in the
+// TrueType / OpenType spec.
+// The data types used are as listed:
+// BYTE       8-bit unsigned integer.
+// CHAR       8-bit signed integer.
+// USHORT     16-bit unsigned integer.
+// SHORT      16-bit signed integer.
+// UINT24     24-bit unsigned integer.
+// ULONG      32-bit unsigned integer.
+// LONG       32-bit signed integer.
+// Fixed      32-bit signed fixed-point number (16.16)
+// FUNIT      Smallest measurable distance in the em space.
+// FWORD      16-bit signed integer (SHORT) that describes a quantity in FUnits.
+// UFWORD     16-bit unsigned integer (USHORT) that describes a quantity in
+//            FUnits.
+// F2DOT14    16-bit signed fixed number with the low 14 bits of fraction (2.14)
+// LONGDATETIME  Date represented in number of seconds since 12:00 midnight,
+//               January 1, 1904. The value is represented as a signed 64-bit
+//               integer.
+
+class ReadableFontData : public FontData,
+                         public RefCounted<ReadableFontData> {
+ public:
+  explicit ReadableFontData(ByteArray* array);
+  virtual ~ReadableFontData();
+
+  static CALLER_ATTACH ReadableFontData* CreateReadableFontData(ByteVector* b);
+
+  // Gets a computed checksum for the data. This checksum uses the OpenType spec
+  // calculation. Every ULong value (32 bit unsigned) in the data is summed and
+  // the resulting value is truncated to 32 bits. If the data length in bytes is
+  // not an integral multiple of 4 then any remaining bytes are treated as the
+  // start of a 4 byte sequence whose remaining bytes are zero.
+  // @return the checksum
+  int64_t Checksum();
+
+  // Sets the bounds to use for computing the checksum. These bounds are in
+  // begin and end pairs. If an odd number is given then the final range is
+  // assumed to extend to the end of the data. The lengths of each range must be
+  // a multiple of 4.
+  // @param ranges the range bounds to use for the checksum
+  void SetCheckSumRanges(const IntegerList& ranges);
+
+  // Read the UBYTE at the given index.
+  // @param index index into the font data
+  // @return the UBYTE; -1 if outside the bounds of the font data
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadUByte(int32_t index);
+
+  // Read the BYTE at the given index.
+  // @param index index into the font data
+  // @return the BYTE
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadByte(int32_t index);
+
+  // Read the bytes at the given index into the array.
+  // @param index index into the font data
+  // @param b the destination for the bytes read
+  // @param offset offset in the byte array to place the bytes
+  // @param length the length of bytes to read
+  // @return the number of bytes actually read; -1 if the index is outside the
+  //         bounds of the font data
+  virtual int32_t ReadBytes(int32_t index,
+                            byte_t* b,
+                            int32_t offset,
+                            int32_t length);
+
+  // Read the CHAR at the given index.
+  // @param index index into the font data
+  // @return the CHAR
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadChar(int32_t index);
+
+  // Read the USHORT at the given index.
+  // @param index index into the font data
+  // @return the USHORT
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadUShort(int32_t index);
+
+  // Read the SHORT at the given index.
+  // @param index index into the font data
+  // @return the SHORT
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadShort(int32_t index);
+
+  // Read the UINT24 at the given index.
+  // @param index index into the font data
+  // @return the UINT24
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadUInt24(int32_t index);
+
+  // Read the ULONG at the given index.
+  // @param index index into the font data
+  // @return the ULONG
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int64_t ReadULong(int32_t index);
+
+  // Read the ULONG at the given index as int32_t.
+  // @param index index into the font data
+  // @return the ULONG
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadULongAsInt(int32_t index);
+
+  // Read the ULONG at the given index, little-endian variant
+  // @param index index into the font data
+  // @return the ULONG
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int64_t ReadULongLE(int32_t index);
+
+  // Read the LONG at the given index.
+  // @param index index into the font data
+  // @return the LONG
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadLong(int32_t index);
+
+  // Read the Fixed at the given index.
+  // @param index index into the font data
+  // @return the Fixed
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadFixed(int32_t index);
+
+  // Read the LONGDATETIME at the given index.
+  // @param index index into the font data
+  // @return the LONGDATETIME
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int64_t ReadDateTimeAsLong(int32_t index);
+
+  // Read the FWORD at the given index.
+  // @param index index into the font data
+  // @return the FWORD
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadFWord(int32_t index);
+
+  // Read the UFWORD at the given index.
+  // @param index index into the font data
+  // @return the UFWORD
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t ReadFUFWord(int32_t index);
+
+  // Note: Not ported because they just throw UnsupportedOperationException()
+  //       in Java.
+  /*
+  virtual int32_t ReadFUnit(int32_t index);
+  virtual int64_t ReadF2Dot14(int32_t index);
+  */
+
+  // Copy the FontData to an OutputStream.
+  // @param os the destination
+  // @return number of bytes copied
+  // @throws IOException
+  virtual int32_t CopyTo(OutputStream* os);
+
+  // Copy the FontData to a WritableFontData.
+  // @param wfd the destination
+  // @return number of bytes copied
+  // @throws IOException
+  virtual int32_t CopyTo(WritableFontData* wfd);
+
+  // Make gcc -Woverloaded-virtual happy.
+  virtual int32_t CopyTo(ByteArray* ba);
+
+  // Search for the key value in the range tables provided.
+  // The search looks through the start-end pairs looking for the key value. It
+  // is assumed that the start-end pairs are both represented by UShort values,
+  // ranges do not overlap, and are monotonically increasing.
+  // @param startIndex the position to read the first start value from
+  // @param startOffset the offset between subsequent start values
+  // @param endIndex the position to read the first end value from
+  // @param endOffset the offset between subsequent end values
+  // @param length the number of start-end pairs
+  // @param key the value to search for
+  // @return the index of the start-end pairs in which the key was found; -1
+  //         otherwise
+  int32_t SearchUShort(int32_t start_index,
+                       int32_t start_offset,
+                       int32_t end_index,
+                       int32_t end_offset,
+                       int32_t length,
+                       int32_t key);
+
+  // Search for the key value in the table provided.
+  // The search looks through the values looking for the key value. It is
+  // assumed that the are represented by UShort values and are monotonically
+  // increasing.
+  // @param startIndex the position to read the first start value from
+  // @param startOffset the offset between subsequent start values
+  // @param length the number of start-end pairs
+  // @param key the value to search for
+  // @return the index of the start-end pairs in which the key was found; -1
+  //         otherwise
+  int32_t SearchUShort(int32_t start_index,
+                       int32_t start_offset,
+                       int32_t length,
+                       int32_t key);
+
+  // Search for the key value in the range tables provided.
+  // The search looks through the start-end pairs looking for the key value. It
+  // is assumed that the start-end pairs are both represented by ULong values
+  // that can be represented within 31 bits, ranges do not overlap, and are
+  // monotonically increasing.
+  // @param startIndex the position to read the first start value from
+  // @param startOffset the offset between subsequent start values
+  // @param endIndex the position to read the first end value from
+  // @param endOffset the offset between subsequent end values
+  // @param length the number of start-end pairs
+  // @param key the value to search for
+  // @return the index of the start-end pairs in which the key was found; -1
+  //         otherwise
+  int32_t SearchULong(int32_t start_index,
+                      int32_t start_offset,
+                      int32_t end_index,
+                      int32_t end_offset,
+                      int32_t length,
+                      int32_t key);
+
+
+  // TODO(arthurhsu): IMPLEMENT
+  /*
+  virtual int32_t ReadFUnit(int32_t index);
+  virtual int64_t ReadF2Dot14(int32_t index);
+  virtual int64_t ReadLongDateTime(int32_t index);
+  */
+
+  // Makes a slice of this FontData. The returned slice will share the data with
+  // the original FontData.
+  // @param offset the start of the slice
+  // @param length the number of bytes in the slice
+  // @return a slice of the original FontData
+  // Note: C++ polymorphism requires return type to be consistent
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length);
+
+  // Makes a bottom bound only slice of this array. The returned slice will
+  // share the data with the original FontData.
+  // @param offset the start of the slice
+  // @return a slice of the original FontData
+  // Note: C++ polymorphism requires return type to be consistent
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset);
+
+  // Not Ported: toString()
+
+ protected:
+  // Constructor. Creates a bounded wrapper of another ReadableFontData from the
+  // given offset until the end of the original ReadableFontData.
+  // @param data data to wrap
+  // @param offset the start of this data's view of the original data
+  ReadableFontData(ReadableFontData* data, int32_t offset);
+
+  // Constructor. Creates a bounded wrapper of another ReadableFontData from the
+  // given offset until the end of the original ReadableFontData.
+  // @param data data to wrap
+  // @param offset the start of this data's view of the original data
+  // @param length the length of the other FontData to use
+  ReadableFontData(ReadableFontData* data, int32_t offset, int32_t length);
+
+ private:
+  // Compute the checksum for the font data using any ranges set for the
+  // calculation.
+  void ComputeChecksum();
+
+  // Do the actual computation of the checksum for a range using the
+  // TrueType/OpenType checksum algorithm. The range used is from the low bound
+  // to the high bound in steps of four bytes. If any of the bytes within that 4
+  // byte segment are not readable then it will considered a zero for
+  // calculation.
+  // Only called from within a synchronized method so it does not need to be
+  // synchronized itself.
+  // @param lowBound first position to start a 4 byte segment on
+  // @param highBound last possible position to start a 4 byte segment on
+  // @return the checksum for the total range
+  int64_t ComputeCheckSum(int32_t low_bound, int32_t high_bound);
+
+  Lock checksum_lock_;
+  bool checksum_set_;
+  int64_t checksum_;
+  IntegerList checksum_range_;
+};
+typedef Ptr<ReadableFontData> ReadableFontDataPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_READABLE_FONT_DATA_H_
diff --git a/cpp/src/sfntly/data/writable_font_data.cc b/cpp/src/sfntly/data/writable_font_data.cc
new file mode 100644
index 0000000..7f6f72f
--- /dev/null
+++ b/cpp/src/sfntly/data/writable_font_data.cc
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/data/writable_font_data.h"
+
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/data/growable_memory_byte_array.h"
+
+namespace sfntly {
+
+WritableFontData::WritableFontData(ByteArray* ba) : ReadableFontData(ba) {
+}
+
+WritableFontData::~WritableFontData() {}
+
+// static
+CALLER_ATTACH
+WritableFontData* WritableFontData::CreateWritableFontData(int32_t length) {
+  ByteArrayPtr ba;
+  if (length > 0) {
+    ba = new MemoryByteArray(length);
+    ba->SetFilledLength(length);
+  } else {
+    ba = new GrowableMemoryByteArray();
+  }
+  WritableFontDataPtr wfd = new WritableFontData(ba);
+  return wfd.Detach();
+}
+
+// TODO(arthurhsu): re-investigate the memory model of this function.  It's
+//                  not too useful without copying, but it's not performance
+//                  savvy to do copying.
+CALLER_ATTACH
+WritableFontData* WritableFontData::CreateWritableFontData(ByteVector* b) {
+  ByteArrayPtr ba = new GrowableMemoryByteArray();
+  ba->Put(0, b);
+  WritableFontDataPtr wfd = new WritableFontData(ba);
+  return wfd.Detach();
+}
+
+int32_t WritableFontData::WriteByte(int32_t index, byte_t b) {
+  array_->Put(BoundOffset(index), b);
+  return 1;
+}
+
+int32_t WritableFontData::WriteBytes(int32_t index,
+                                     byte_t* b,
+                                     int32_t offset,
+                                     int32_t length) {
+  return array_->Put(BoundOffset(index),
+                     b,
+                     offset,
+                     BoundLength(index, length));
+}
+
+int32_t WritableFontData::WriteBytes(int32_t index, ByteVector* b) {
+  assert(b);
+  return WriteBytes(index, &((*b)[0]), 0, b->size());
+}
+
+int32_t WritableFontData::WriteBytesPad(int32_t index,
+                                        ByteVector* b,
+                                        int32_t offset,
+                                        int32_t length,
+                                        byte_t pad) {
+  int32_t written =
+      array_->Put(BoundOffset(index),
+                  &((*b)[0]),
+                  offset,
+                  BoundLength(index,
+                              std::min<int32_t>(length, b->size() - offset)));
+  written += WritePadding(written + index, length - written, pad);
+  return written;
+}
+
+int32_t WritableFontData::WritePadding(int32_t index, int32_t count) {
+  return WritePadding(index, count, (byte_t)0);
+}
+
+int32_t WritableFontData::WritePadding(int32_t index, int32_t count,
+                                       byte_t pad) {
+  for (int32_t i = 0; i < count; ++i) {
+    array_->Put(index + i, pad);
+  }
+  return count;
+}
+
+int32_t WritableFontData::WriteChar(int32_t index, byte_t c) {
+  return WriteByte(index, c);
+}
+
+int32_t WritableFontData::WriteUShort(int32_t index, int32_t us) {
+  WriteByte(index, (byte_t)((us >> 8) & 0xff));
+  WriteByte(index + 1, (byte_t)(us & 0xff));
+  return 2;
+}
+
+int32_t WritableFontData::WriteUShortLE(int32_t index, int32_t us) {
+  WriteByte(index, (byte_t)(us & 0xff));
+  WriteByte(index + 1, (byte_t)((us >> 8) & 0xff));
+  return 2;
+}
+
+int32_t WritableFontData::WriteShort(int32_t index, int32_t s) {
+  return WriteUShort(index, s);
+}
+
+int32_t WritableFontData::WriteUInt24(int32_t index, int32_t ui) {
+  WriteByte(index, (byte_t)((ui >> 16) & 0xff));
+  WriteByte(index + 1, (byte_t)((ui >> 8) & 0xff));
+  WriteByte(index + 2, (byte_t)(ui & 0xff));
+  return 3;
+}
+
+int32_t WritableFontData::WriteULong(int32_t index, int64_t ul) {
+  WriteByte(index, (byte_t)((ul >> 24) & 0xff));
+  WriteByte(index + 1, (byte_t)((ul >> 16) & 0xff));
+  WriteByte(index + 2, (byte_t)((ul >> 8) & 0xff));
+  WriteByte(index + 3, (byte_t)(ul & 0xff));
+  return 4;
+}
+
+int32_t WritableFontData::WriteULongLE(int32_t index, int64_t ul) {
+  WriteByte(index, (byte_t)(ul & 0xff));
+  WriteByte(index + 1, (byte_t)((ul >> 8) & 0xff));
+  WriteByte(index + 2, (byte_t)((ul >> 16) & 0xff));
+  WriteByte(index + 3, (byte_t)((ul >> 24) & 0xff));
+  return 4;
+}
+
+int32_t WritableFontData::WriteLong(int32_t index, int64_t l) {
+  return WriteULong(index, l);
+}
+
+int32_t WritableFontData::WriteFixed(int32_t index, int32_t f) {
+  return WriteLong(index, f);
+}
+
+int32_t WritableFontData::WriteDateTime(int32_t index, int64_t date) {
+  WriteULong(index, (date >> 32) & 0xffffffff);
+  WriteULong(index + 4, date & 0xffffffff);
+  return 8;
+}
+
+void WritableFontData::CopyFrom(InputStream* is, int32_t length) {
+  array_->CopyFrom(is, length);
+}
+
+void WritableFontData::CopyFrom(InputStream* is) {
+  array_->CopyFrom(is);
+}
+
+CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset,
+                                                int32_t length) {
+  if (offset < 0 || offset + length > Size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException(
+        "Attempt to bind data outside of its limits");
+#endif
+    return NULL;
+  }
+  FontDataPtr slice = new WritableFontData(this, offset, length);
+  return slice.Detach();
+}
+
+CALLER_ATTACH FontData* WritableFontData::Slice(int32_t offset) {
+  if (offset > Size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException(
+        "Attempt to bind data outside of its limits");
+#endif
+    return NULL;
+  }
+  FontDataPtr slice = new WritableFontData(this, offset);
+  return slice.Detach();
+}
+
+WritableFontData::WritableFontData(WritableFontData* data, int32_t offset)
+    : ReadableFontData(data, offset) {
+}
+
+WritableFontData::WritableFontData(WritableFontData* data,
+                                   int32_t offset,
+                                   int32_t length)
+    : ReadableFontData(data, offset, length) {
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/data/writable_font_data.h b/cpp/src/sfntly/data/writable_font_data.h
new file mode 100644
index 0000000..d2a049e
--- /dev/null
+++ b/cpp/src/sfntly/data/writable_font_data.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_
+#define SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_
+
+#include "sfntly/data/readable_font_data.h"
+
+namespace sfntly {
+
+// Writable font data wrapper. Supports writing of data primitives in the
+// TrueType / OpenType spec.
+class WritableFontData : public ReadableFontData {
+ public:
+  explicit WritableFontData(ByteArray* ba);
+  virtual ~WritableFontData();
+
+  // Constructs a writable font data object. If the length is specified as
+  // positive then a fixed size font data object will be created. If the length
+  // is zero or less then a growable font data object will be created and the
+  // size will be used as an estimate to help in allocating the original space.
+  // @param length if length > 0 create a fixed length font data; otherwise
+  //        create a growable font data
+  // @return a new writable font data
+  static CALLER_ATTACH WritableFontData* CreateWritableFontData(int32_t length);
+
+  // Constructs a writable font data object. The new font data object will wrap
+  // the bytes passed in to the factory and it will take make a copy of those
+  // bytes.
+  // @param b the byte vector to wrap
+  // @return a new writable font data
+  static CALLER_ATTACH WritableFontData* CreateWritableFontData(ByteVector* b);
+
+  // Write a byte at the given index.
+  // @param index index into the font data
+  // @param b the byte to write
+  // @return the number of bytes written
+  virtual int32_t WriteByte(int32_t index, byte_t b);
+
+  // Write the bytes from the array.
+  // @param index index into the font data
+  // @param b the source for the bytes to be written
+  // @param offset offset in the byte array
+  // @param length the length of the bytes to be written
+  // @return the number of bytes actually written; -1 if the index is outside
+  //         the FontData's range
+  virtual int32_t WriteBytes(int32_t index,
+                             byte_t* b,
+                             int32_t offset,
+                             int32_t length);
+
+  // Write the bytes from the array.
+  // @param index index into the font data
+  // @param b the source for the bytes to be written
+  // @return the number of bytes actually written; -1 if the index is outside
+  //         the FontData's range
+  virtual int32_t WriteBytes(int32_t index, ByteVector* b);
+
+  // Write the bytes from the array and pad if necessary.
+  // Write to the length given using the byte array provided and if there are
+  // not enough bytes in the array then pad to the requested length using the
+  // pad byte specified.
+  // @param index index into the font data
+  // @param b the source for the bytes to be written
+  // @param offset offset in the byte array
+  // @param length the length of the bytes to be written
+  // @param pad the padding byte to be used if necessary
+  // @return the number of bytes actually written
+  virtual int32_t WriteBytesPad(int32_t index,
+                                ByteVector* b,
+                                int32_t offset,
+                                int32_t length,
+                                byte_t pad);
+
+  // Writes padding to the FontData. The padding byte written is 0x00.
+  // @param index index into the font data
+  // @param count the number of pad bytes to write
+  // @return the number of pad bytes written
+  virtual int32_t WritePadding(int32_t index, int32_t count);
+
+  // Writes padding to the FontData.
+  // @param index index into the font data
+  // @param count the number of pad bytes to write
+  // @param pad the byte value to use as padding
+  // @return the number of pad bytes written
+  virtual int32_t WritePadding(int32_t index, int32_t count, byte_t pad);
+
+  // Write the CHAR at the given index.
+  // @param index index into the font data
+  // @param c the CHAR
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteChar(int32_t index, byte_t c);
+
+  // Write the USHORT at the given index.
+  // @param index index into the font data
+  // @param us the USHORT
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteUShort(int32_t index, int32_t us);
+
+  // Write the USHORT at the given index in little endian format.
+  // @param index index into the font data
+  // @param us the USHORT
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteUShortLE(int32_t index, int32_t us);
+
+  // Write the SHORT at the given index.
+  // @param index index into the font data
+  // @param s the SHORT
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteShort(int32_t index, int32_t s);
+
+  // Write the UINT24 at the given index.
+  // @param index index into the font data
+  // @param ui the UINT24
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteUInt24(int32_t index, int32_t ui);
+
+  // Write the ULONG at the given index.
+  // @param index index into the font data
+  // @param ul the ULONG
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteULong(int32_t index, int64_t ul);
+
+  // Write the ULONG at the given index in little endian format.
+  // @param index index into the font data
+  // @param ul the ULONG
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteULongLE(int32_t index, int64_t ul);
+
+  // Write the LONG at the given index.
+  // @param index index into the font data
+  // @param l the LONG
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteLong(int32_t index, int64_t l);
+
+  // Write the Fixed at the given index.
+  // @param index index into the font data
+  // @param f the Fixed
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteFixed(int32_t index, int32_t f);
+
+  // Write the LONGDATETIME at the given index.
+  // @param index index into the font data
+  // @param date the LONGDATETIME
+  // @return the number of bytes actually written
+  // @throws IndexOutOfBoundsException if index is outside the FontData's range
+  virtual int32_t WriteDateTime(int32_t index, int64_t date);
+
+  // Copy from the InputStream into this FontData.
+  // @param is the source
+  // @param length the number of bytes to copy
+  // @throws IOException
+  virtual void CopyFrom(InputStream* is, int32_t length);
+
+  // Copy everything from the InputStream into this FontData.
+  // @param is the source
+  // @throws IOException
+  virtual void CopyFrom(InputStream* is);
+
+  // Makes a slice of this FontData. The returned slice will share the data with
+  // the original FontData.
+  // @param offset the start of the slice
+  // @param length the number of bytes in the slice
+  // @return a slice of the original FontData
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset, int32_t length);
+
+  // Makes a bottom bound only slice of this array. The returned slice will
+  // share the data with the original FontData.
+  // @param offset the start of the slice
+  // @return a slice of the original FontData
+  virtual CALLER_ATTACH FontData* Slice(int32_t offset);
+
+ private:
+  // Constructor with a lower bound.
+  // @param data other WritableFontData object to share data with
+  // @param offset offset from the other WritableFontData's data
+  WritableFontData(WritableFontData* data, int32_t offset);
+
+  // Constructor with lower bound and a length bound.
+  // @param data other WritableFontData object to share data with
+  // @param offset offset from the other WritableFontData's data
+  // @param length length of other WritableFontData's data to use
+  WritableFontData(WritableFontData* data, int32_t offset, int32_t length);
+};
+typedef Ptr<WritableFontData> WritableFontDataPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_DATA_WRITABLE_FONT_DATA_H_
diff --git a/cpp/src/sfntly/font.cc b/cpp/src/sfntly/font.cc
new file mode 100644
index 0000000..347e0c1
--- /dev/null
+++ b/cpp/src/sfntly/font.cc
@@ -0,0 +1,557 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/font.h"
+
+#include <stdio.h>
+
+#include <functional>
+#include <algorithm>
+#include <map>
+#include <string>
+#include <typeinfo>
+#include <iterator>
+
+#include "sfntly/data/font_input_stream.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/math/fixed1616.h"
+#include "sfntly/math/font_math.h"
+#include "sfntly/port/exception_type.h"
+#include "sfntly/table/core/font_header_table.h"
+#include "sfntly/table/core/horizontal_device_metrics_table.h"
+#include "sfntly/table/core/horizontal_header_table.h"
+#include "sfntly/table/core/horizontal_metrics_table.h"
+#include "sfntly/table/core/maximum_profile_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+#include "sfntly/tag.h"
+
+namespace sfntly {
+
+const int32_t SFNTVERSION_MAJOR = 1;
+const int32_t SFNTVERSION_MINOR = 0;
+
+/******************************************************************************
+ * Font class
+ ******************************************************************************/
+Font::~Font() {}
+
+bool Font::HasTable(int32_t tag) {
+  TableMap::const_iterator result = tables_.find(tag);
+  TableMap::const_iterator end = tables_.end();
+  return (result != end);
+}
+
+Table* Font::GetTable(int32_t tag) {
+  if (!HasTable(tag)) {
+    return NULL;
+  }
+  return tables_[tag];
+}
+
+const TableMap* Font::GetTableMap() {
+  return &tables_;
+}
+
+void Font::Serialize(OutputStream* os, IntegerList* table_ordering) {
+  assert(table_ordering);
+  IntegerList final_table_ordering;
+  GenerateTableOrdering(table_ordering, &final_table_ordering);
+  TableHeaderList table_records;
+  BuildTableHeadersForSerialization(&final_table_ordering, &table_records);
+
+  FontOutputStream fos(os);
+  SerializeHeader(&fos, &table_records);
+  SerializeTables(&fos, &table_records);
+}
+
+Font::Font(int32_t sfnt_version, ByteVector* digest)
+    : sfnt_version_(sfnt_version) {
+  // non-trivial assignments that makes debugging hard if placed in
+  // initialization list
+  digest_ = *digest;
+}
+
+void Font::BuildTableHeadersForSerialization(IntegerList* table_ordering,
+                                             TableHeaderList* table_headers) {
+  assert(table_headers);
+  assert(table_ordering);
+
+  IntegerList final_table_ordering;
+  GenerateTableOrdering(table_ordering, &final_table_ordering);
+  int32_t table_offset = Offset::kTableRecordBegin + num_tables() *
+                         Offset::kTableRecordSize;
+  for (IntegerList::iterator tag = final_table_ordering.begin(),
+                             tag_end = final_table_ordering.end();
+                             tag != tag_end; ++tag) {
+    if (tables_.find(*tag) == tables_.end()) {
+      continue;
+    }
+    TablePtr table = tables_[*tag];
+    if (table != NULL) {
+      HeaderPtr header =
+          new Header(*tag, table->CalculatedChecksum(), table_offset,
+                     table->header()->length());
+      table_headers->push_back(header);
+      table_offset += (table->DataLength() + 3) & ~3;
+    }
+  }
+}
+
+void Font::SerializeHeader(FontOutputStream* fos,
+                           TableHeaderList* table_headers) {
+  fos->WriteFixed(sfnt_version_);
+  fos->WriteUShort(table_headers->size());
+  int32_t log2_of_max_power_of_2 = FontMath::Log2(table_headers->size());
+  int32_t search_range = 2 << (log2_of_max_power_of_2 - 1 + 4);
+  fos->WriteUShort(search_range);
+  fos->WriteUShort(log2_of_max_power_of_2);
+  fos->WriteUShort((table_headers->size() * 16) - search_range);
+
+  HeaderTagSortedSet sorted_headers;
+  std::copy(table_headers->begin(),
+            table_headers->end(),
+            std::inserter(sorted_headers, sorted_headers.end()));
+
+  for (HeaderTagSortedSet::iterator record = sorted_headers.begin(),
+                                    record_end = sorted_headers.end();
+                                    record != record_end; ++record) {
+    fos->WriteULong((*record)->tag());
+    fos->WriteULong((int32_t)((*record)->checksum()));
+    fos->WriteULong((*record)->offset());
+    fos->WriteULong((*record)->length());
+  }
+}
+
+void Font::SerializeTables(FontOutputStream* fos,
+                           TableHeaderList* table_headers) {
+  assert(fos);
+  assert(table_headers);
+  for (TableHeaderList::iterator record = table_headers->begin(),
+                                 end_of_headers = table_headers->end();
+                                 record != end_of_headers; ++record) {
+    TablePtr target_table = GetTable((*record)->tag());
+    if (target_table == NULL) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IOException("Table out of sync with font header.");
+#endif
+      return;
+    }
+    int32_t table_size = target_table->Serialize(fos);
+    if (table_size != (*record)->length()) {
+      assert(false);
+    }
+    int32_t filler_size = ((table_size + 3) & ~3) - table_size;
+    for (int32_t i = 0; i < filler_size; ++i) {
+      fos->Write(static_cast<byte_t>(0));
+    }
+  }
+}
+
+void Font::GenerateTableOrdering(IntegerList* default_table_ordering,
+                                 IntegerList* table_ordering) {
+  assert(default_table_ordering);
+  assert(table_ordering);
+  table_ordering->clear();
+  if (default_table_ordering->empty()) {
+    DefaultTableOrdering(default_table_ordering);
+  }
+
+  typedef std::map<int32_t, bool> Int2Bool;
+  typedef std::pair<int32_t, bool> Int2BoolEntry;
+  Int2Bool tables_in_font;
+  for (TableMap::iterator table = tables_.begin(), table_end = tables_.end();
+                          table != table_end; ++table) {
+    tables_in_font.insert(Int2BoolEntry(table->first, false));
+  }
+  for (IntegerList::iterator tag = default_table_ordering->begin(),
+                             tag_end = default_table_ordering->end();
+                             tag != tag_end; ++tag) {
+    if (HasTable(*tag)) {
+      table_ordering->push_back(*tag);
+      tables_in_font[*tag] = true;
+    }
+  }
+  for (Int2Bool::iterator table = tables_in_font.begin(),
+                          table_end = tables_in_font.end();
+                          table != table_end; ++table) {
+    if (table->second == false)
+      table_ordering->push_back(table->first);
+  }
+}
+
+void Font::DefaultTableOrdering(IntegerList* default_table_ordering) {
+  assert(default_table_ordering);
+  default_table_ordering->clear();
+  if (HasTable(Tag::CFF)) {
+    default_table_ordering->resize(CFF_TABLE_ORDERING_SIZE);
+    std::copy(CFF_TABLE_ORDERING, CFF_TABLE_ORDERING + CFF_TABLE_ORDERING_SIZE,
+              default_table_ordering->begin());
+    return;
+  }
+  default_table_ordering->resize(TRUE_TYPE_TABLE_ORDERING_SIZE);
+  std::copy(TRUE_TYPE_TABLE_ORDERING,
+            TRUE_TYPE_TABLE_ORDERING + TRUE_TYPE_TABLE_ORDERING_SIZE,
+            default_table_ordering->begin());
+}
+
+/******************************************************************************
+ * Font::Builder class
+ ******************************************************************************/
+Font::Builder::~Builder() {}
+
+CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(FontFactory* factory,
+                                                          InputStream* is) {
+  FontBuilderPtr builder = new Builder(factory);
+  builder->LoadFont(is);
+  return builder.Detach();
+}
+
+CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(
+    FontFactory* factory,
+    WritableFontData* wfd,
+    int32_t offset_to_offset_table) {
+  FontBuilderPtr builder = new Builder(factory);
+  builder->LoadFont(wfd, offset_to_offset_table);
+  return builder.Detach();
+}
+
+CALLER_ATTACH Font::Builder* Font::Builder::GetOTFBuilder(
+    FontFactory* factory) {
+  FontBuilderPtr builder = new Builder(factory);
+  return builder.Detach();
+}
+
+bool Font::Builder::ReadyToBuild() {
+  // just read in data with no manipulation
+  if (table_builders_.empty() && !data_blocks_.empty()) {
+    return true;
+  }
+
+  // TODO(stuartg): font level checks - required tables etc?
+  for (TableBuilderMap::iterator table_builder = table_builders_.begin(),
+                                 table_builder_end = table_builders_.end();
+                                 table_builder != table_builder_end;
+                                 ++table_builder) {
+    if (!table_builder->second->ReadyToBuild())
+      return false;
+  }
+  return true;
+}
+
+CALLER_ATTACH Font* Font::Builder::Build() {
+  FontPtr font = new Font(sfnt_version_, &digest_);
+
+  if (!table_builders_.empty()) {
+    // Note: Different from Java. Directly use font->tables_ here to avoid
+    //       STL container copying.
+    BuildTablesFromBuilders(font, &table_builders_, &font->tables_);
+  }
+
+  table_builders_.clear();
+  data_blocks_.clear();
+  return font.Detach();
+}
+
+void Font::Builder::SetDigest(ByteVector* digest) {
+  digest_.clear();
+  digest_ = *digest;
+}
+
+void Font::Builder::ClearTableBuilders() {
+  table_builders_.clear();
+}
+
+bool Font::Builder::HasTableBuilder(int32_t tag) {
+  return (table_builders_.find(tag) != table_builders_.end());
+}
+
+Table::Builder* Font::Builder::GetTableBuilder(int32_t tag) {
+  if (HasTableBuilder(tag))
+    return table_builders_[tag];
+  return NULL;
+}
+
+Table::Builder* Font::Builder::NewTableBuilder(int32_t tag) {
+  HeaderPtr header = new Header(tag);
+  TableBuilderPtr builder;
+  builder.Attach(Table::Builder::GetBuilder(header, NULL));
+  table_builders_.insert(TableBuilderEntry(header->tag(), builder));
+  return builder;
+}
+
+Table::Builder* Font::Builder::NewTableBuilder(int32_t tag,
+                                               ReadableFontData* src_data) {
+  assert(src_data);
+  WritableFontDataPtr data;
+  data.Attach(WritableFontData::CreateWritableFontData(src_data->Length()));
+  // TODO(stuarg): take over original data instead?
+  src_data->CopyTo(data);
+
+  HeaderPtr header = new Header(tag, data->Length());
+  TableBuilderPtr builder;
+  builder.Attach(Table::Builder::GetBuilder(header, data));
+  table_builders_.insert(TableBuilderEntry(tag, builder));
+  return builder;
+}
+
+void Font::Builder::RemoveTableBuilder(int32_t tag) {
+  TableBuilderMap::iterator target = table_builders_.find(tag);
+  if (target != table_builders_.end()) {
+    table_builders_.erase(target);
+  }
+}
+
+Font::Builder::Builder(FontFactory* factory)
+    : factory_(factory),
+      sfnt_version_(Fixed1616::Fixed(SFNTVERSION_MAJOR, SFNTVERSION_MINOR)) {
+}
+
+void Font::Builder::LoadFont(InputStream* is) {
+  // Note: we do not throw exception here for is.  This is more of an assertion.
+  assert(is);
+  FontInputStream font_is(is);
+  HeaderOffsetSortedSet records;
+  ReadHeader(&font_is, &records);
+  LoadTableData(&records, &font_is, &data_blocks_);
+  BuildAllTableBuilders(&data_blocks_, &table_builders_);
+  font_is.Close();
+}
+
+void Font::Builder::LoadFont(WritableFontData* wfd,
+                             int32_t offset_to_offset_table) {
+  // Note: we do not throw exception here for is.  This is more of an assertion.
+  assert(wfd);
+  HeaderOffsetSortedSet records;
+  ReadHeader(wfd, offset_to_offset_table, &records);
+  LoadTableData(&records, wfd, &data_blocks_);
+  BuildAllTableBuilders(&data_blocks_, &table_builders_);
+}
+
+int32_t Font::Builder::SfntWrapperSize() {
+  return Offset::kSfntHeaderSize +
+         (Offset::kTableRecordSize * table_builders_.size());
+}
+
+void Font::Builder::BuildAllTableBuilders(DataBlockMap* table_data,
+                                          TableBuilderMap* builder_map) {
+  for (DataBlockMap::iterator record = table_data->begin(),
+                              record_end = table_data->end();
+                              record != record_end; ++record) {
+    TableBuilderPtr builder;
+    builder.Attach(GetTableBuilder(record->first.p_, record->second.p_));
+    builder_map->insert(TableBuilderEntry(record->first->tag(), builder));
+  }
+  InterRelateBuilders(&table_builders_);
+}
+
+CALLER_ATTACH
+Table::Builder* Font::Builder::GetTableBuilder(Header* header,
+                                               WritableFontData* data) {
+  return Table::Builder::GetBuilder(header, data);
+}
+
+void Font::Builder::BuildTablesFromBuilders(Font* font,
+                                            TableBuilderMap* builder_map,
+                                            TableMap* table_map) {
+  UNREFERENCED_PARAMETER(font);
+  InterRelateBuilders(builder_map);
+
+  // Now build all the tables.
+  for (TableBuilderMap::iterator builder = builder_map->begin(),
+                                 builder_end = builder_map->end();
+                                 builder != builder_end; ++builder) {
+    TablePtr table;
+    if (builder->second && builder->second->ReadyToBuild()) {
+      table.Attach(down_cast<Table*>(builder->second->Build()));
+    }
+    if (table == NULL) {
+      table_map->clear();
+#if !defined (SFNTLY_NO_EXCEPTION)
+      std::string builder_string = "Unable to build table - ";
+      char* table_name = TagToString(builder->first);
+      builder_string += table_name;
+      delete[] table_name;
+      throw RuntimeException(builder_string.c_str());
+#endif
+      return;
+    }
+    table_map->insert(TableMapEntry(table->header()->tag(), table));
+  }
+}
+
+static Table::Builder* GetBuilder(TableBuilderMap* builder_map, int32_t tag) {
+  if (builder_map) {
+    TableBuilderMap::iterator target = builder_map->find(tag);
+    if (target != builder_map->end()) {
+      return target->second.p_;
+    }
+  }
+
+  return NULL;
+}
+
+void Font::Builder::InterRelateBuilders(TableBuilderMap* builder_map) {
+  Table::Builder* raw_head_builder = GetBuilder(builder_map, Tag::head);
+  FontHeaderTableBuilderPtr header_table_builder;
+  if (raw_head_builder != NULL) {
+      header_table_builder =
+          down_cast<FontHeaderTable::Builder*>(raw_head_builder);
+  }
+
+  Table::Builder* raw_hhea_builder = GetBuilder(builder_map, Tag::hhea);
+  HorizontalHeaderTableBuilderPtr horizontal_header_builder;
+  if (raw_head_builder != NULL) {
+      horizontal_header_builder =
+          down_cast<HorizontalHeaderTable::Builder*>(raw_hhea_builder);
+  }
+
+  Table::Builder* raw_maxp_builder = GetBuilder(builder_map, Tag::maxp);
+  MaximumProfileTableBuilderPtr max_profile_builder;
+  if (raw_maxp_builder != NULL) {
+      max_profile_builder =
+          down_cast<MaximumProfileTable::Builder*>(raw_maxp_builder);
+  }
+
+  Table::Builder* raw_loca_builder = GetBuilder(builder_map, Tag::loca);
+  LocaTableBuilderPtr loca_table_builder;
+  if (raw_loca_builder != NULL) {
+      loca_table_builder = down_cast<LocaTable::Builder*>(raw_loca_builder);
+  }
+
+  Table::Builder* raw_hmtx_builder = GetBuilder(builder_map, Tag::hmtx);
+  HorizontalMetricsTableBuilderPtr horizontal_metrics_builder;
+  if (raw_hmtx_builder != NULL) {
+      horizontal_metrics_builder =
+          down_cast<HorizontalMetricsTable::Builder*>(raw_hmtx_builder);
+  }
+
+#if defined (SFNTLY_EXPERIMENTAL)
+  Table::Builder* raw_hdmx_builder = GetBuilder(builder_map, Tag::hdmx);
+  HorizontalDeviceMetricsTableBuilderPtr hdmx_table_builder;
+  if (raw_hdmx_builder != NULL) {
+      hdmx_table_builder =
+          down_cast<HorizontalDeviceMetricsTable::Builder*>(raw_hdmx_builder);
+  }
+#endif
+
+  // set the inter table data required to build certain tables
+  if (horizontal_metrics_builder != NULL) {
+    if (max_profile_builder != NULL) {
+      horizontal_metrics_builder->SetNumGlyphs(
+          max_profile_builder->NumGlyphs());
+    }
+    if (horizontal_header_builder != NULL) {
+      horizontal_metrics_builder->SetNumberOfHMetrics(
+          horizontal_header_builder->NumberOfHMetrics());
+    }
+  }
+
+  if (loca_table_builder != NULL) {
+    if (max_profile_builder != NULL) {
+      loca_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs());
+    }
+    if (header_table_builder != NULL) {
+      loca_table_builder->set_format_version(
+          header_table_builder->IndexToLocFormat());
+    }
+  }
+
+#if defined (SFNTLY_EXPERIMENTAL)
+  // Note: In C++, hdmx_table_builder can be NULL in a subsetter.
+  if (max_profile_builder != NULL && hdmx_table_builder != NULL) {
+    hdmx_table_builder->SetNumGlyphs(max_profile_builder->NumGlyphs());
+  }
+#endif
+}
+
+void Font::Builder::ReadHeader(FontInputStream* is,
+                               HeaderOffsetSortedSet* records) {
+  assert(records);
+  sfnt_version_ = is->ReadFixed();
+  num_tables_ = is->ReadUShort();
+  search_range_ = is->ReadUShort();
+  entry_selector_ = is->ReadUShort();
+  range_shift_ = is->ReadUShort();
+
+  for (int32_t table_number = 0; table_number < num_tables_; ++table_number) {
+    // Need to use temporary vars here.  C++ evaluates function parameters from
+    // right to left and thus breaks the order of input stream.
+    int32_t tag = is->ReadULongAsInt();
+    int64_t checksum = is->ReadULong();
+    int32_t offset = is->ReadULongAsInt();
+    int32_t length = is->ReadULongAsInt();
+    HeaderPtr table = new Header(tag, checksum, offset, length);
+    records->insert(table);
+  }
+}
+
+void Font::Builder::ReadHeader(ReadableFontData* fd,
+                               int32_t offset,
+                               HeaderOffsetSortedSet* records) {
+  assert(records);
+  sfnt_version_ = fd->ReadFixed(offset + Offset::kSfntVersion);
+  num_tables_ = fd->ReadUShort(offset + Offset::kNumTables);
+  search_range_ = fd->ReadUShort(offset + Offset::kSearchRange);
+  entry_selector_ = fd->ReadUShort(offset + Offset::kEntrySelector);
+  range_shift_ = fd->ReadUShort(offset + Offset::kRangeShift);
+
+  int32_t table_offset = offset + Offset::kTableRecordBegin;
+  for (int32_t table_number = 0;
+       table_number < num_tables_;
+       table_number++, table_offset += Offset::kTableRecordSize) {
+    int32_t tag = fd->ReadULongAsInt(table_offset + Offset::kTableTag);
+    int64_t checksum = fd->ReadULong(table_offset + Offset::kTableCheckSum);
+    int32_t offset = fd->ReadULongAsInt(table_offset + Offset::kTableOffset);
+    int32_t length = fd->ReadULongAsInt(table_offset + Offset::kTableLength);
+    HeaderPtr table = new Header(tag, checksum, offset, length);
+    records->insert(table);
+  }
+}
+
+void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers,
+                                  FontInputStream* is,
+                                  DataBlockMap* table_data) {
+  assert(table_data);
+  for (HeaderOffsetSortedSet::iterator table_header = headers->begin(),
+                                       table_end = headers->end();
+                                       table_header != table_end;
+                                       ++table_header) {
+    is->Skip((*table_header)->offset() - is->position());
+    FontInputStream table_is(is, (*table_header)->length());
+    WritableFontDataPtr data;
+    data.Attach(
+        WritableFontData::CreateWritableFontData((*table_header)->length()));
+    data->CopyFrom(&table_is, (*table_header)->length());
+    table_data->insert(DataBlockEntry(*table_header, data));
+  }
+}
+
+void Font::Builder::LoadTableData(HeaderOffsetSortedSet* headers,
+                                  WritableFontData* fd,
+                                  DataBlockMap* table_data) {
+  for (HeaderOffsetSortedSet::iterator table_header = headers->begin(),
+                                       table_end = headers->end();
+                                       table_header != table_end;
+                                       ++table_header) {
+    FontDataPtr sliced_data;
+    sliced_data.Attach(
+        fd->Slice((*table_header)->offset(), (*table_header)->length()));
+    WritableFontDataPtr data = down_cast<WritableFontData*>(sliced_data.p_);
+    table_data->insert(DataBlockEntry(*table_header, data));
+  }
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/font.h b/cpp/src/sfntly/font.h
new file mode 100644
index 0000000..975e8cc
--- /dev/null
+++ b/cpp/src/sfntly/font.h
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_FONT_H_
+#define SFNTLY_CPP_SRC_SFNTLY_FONT_H_
+
+#include <vector>
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/endian.h"
+#include "sfntly/data/font_input_stream.h"
+#include "sfntly/data/font_output_stream.h"
+#include "sfntly/data/writable_font_data.h"
+#include "sfntly/table/table.h"
+
+namespace sfntly {
+
+// Note: following constants are embedded in Font class in Java.  They are
+//       extracted out for easier reference from other classes.  Offset is the
+//       one that is kept within class.
+// Platform ids. These are used in a number of places within the font whenever
+// the platform needs to be specified.
+struct PlatformId {
+  enum {
+    kUnknown = -1,
+    kUnicode = 0,
+    kMacintosh = 1,
+    kISO = 2,
+    kWindows = 3,
+    kCustom = 4
+  };
+};
+
+// Unicode encoding ids. These are used in a number of places within the font
+// whenever character encodings need to be specified.
+struct UnicodeEncodingId {
+  enum {
+    kUnknown = -1,
+    kUnicode1_0 = 0,
+    kUnicode1_1 = 1,
+    kISO10646 = 2,
+    kUnicode2_0_BMP = 3,
+    kUnicode2_0 = 4,
+    kUnicodeVariationSequences = 5
+  };
+};
+
+// Windows encoding ids. These are used in a number of places within the font
+// whenever character encodings need to be specified.
+struct WindowsEncodingId {
+  enum {
+    kUnknown = 0xffffffff,
+    kSymbol = 0,
+    kUnicodeUCS2 = 1,
+    kShiftJIS = 2,
+    kPRC = 3,
+    kBig5 = 4,
+    kWansung = 5,
+    kJohab = 6,
+    kUnicodeUCS4 = 10
+  };
+};
+
+// Macintosh encoding ids. These are used in a number of places within the
+// font whenever character encodings need to be specified.
+struct MacintoshEncodingId {
+  // Macintosh Platform Encodings
+  enum {
+    kUnknown = -1,
+    kRoman = 0,
+    kJapanese = 1,
+    kChineseTraditional = 2,
+    kKorean = 3,
+    kArabic = 4,
+    kHebrew = 5,
+    kGreek = 6,
+    kRussian = 7,
+    kRSymbol = 8,
+    kDevanagari = 9,
+    kGurmukhi = 10,
+    kGujarati = 11,
+    kOriya = 12,
+    kBengali = 13,
+    kTamil = 14,
+    kTelugu = 15,
+    kKannada = 16,
+    kMalayalam = 17,
+    kSinhalese = 18,
+    kBurmese = 19,
+    kKhmer = 20,
+    kThai = 21,
+    kLaotian = 22,
+    kGeorgian = 23,
+    kArmenian = 24,
+    kChineseSimplified = 25,
+    kTibetan = 26,
+    kMongolian = 27,
+    kGeez = 28,
+    kSlavic = 29,
+    kVietnamese = 30,
+    kSindhi = 31,
+    kUninterpreted = 32
+  };
+};
+
+class FontFactory;
+
+// An sfnt container font object. This object is immutable and thread safe. To
+// construct one use an instance of Font::Builder.
+class Font : public RefCounted<Font> {
+ public:
+  // A builder for a font object. The builder allows the for the creation of
+  // immutable Font objects. The builder is a one use non-thread safe object and
+  // once the Font object has been created it is no longer usable. To create a
+  // further Font object new builder will be required.
+  class Builder : public RefCounted<Builder> {
+   public:
+    virtual ~Builder();
+
+    static CALLER_ATTACH Builder*
+        GetOTFBuilder(FontFactory* factory, InputStream* is);
+    static CALLER_ATTACH Builder*
+        GetOTFBuilder(FontFactory* factory,
+                      WritableFontData* ba,
+                      int32_t offset_to_offset_table);
+    static CALLER_ATTACH Builder* GetOTFBuilder(FontFactory* factory);
+
+    // Get the font factory that created this font builder.
+    FontFactory* GetFontFactory() { return factory_; }
+
+    // Is the font ready to build?
+    bool ReadyToBuild();
+
+    // Build the Font. After this call this builder will no longer be usable.
+    CALLER_ATTACH Font* Build();
+
+    // Set a unique fingerprint for the font object.
+    void SetDigest(ByteVector* digest);
+
+    // Clear all table builders.
+    void ClearTableBuilders();
+
+    // Does this font builder have the specified table builder.
+    bool HasTableBuilder(int32_t tag);
+
+    // Get the table builder for the given tag. If there is no builder for that
+    // tag then return a null.
+    Table::Builder* GetTableBuilder(int32_t tag);
+
+    // Creates a new table builder for the table type given by the table id tag.
+    // This new table has been added to the font and will replace any existing
+    // builder for that table.
+    // @return new empty table of the type specified by tag; if tag is not known
+    //         then a generic OpenTypeTable is returned
+    virtual Table::Builder* NewTableBuilder(int32_t tag);
+
+    // Creates a new table builder for the table type given by the table id tag.
+    // It makes a copy of the data provided and uses that copy for the table.
+    // This new table has been added to the font and will replace any existing
+    // builder for that table.
+    virtual Table::Builder* NewTableBuilder(int32_t tag,
+                                            ReadableFontData* src_data);
+
+    // Get a map of the table builders in this font builder accessed by table
+    // tag.
+    virtual TableBuilderMap* table_builders() { return &table_builders_; }
+
+    // Remove the specified table builder from the font builder.
+    // Note: different from Java: we don't return object in removeTableBuilder
+    virtual void RemoveTableBuilder(int32_t tag);
+
+    // Get the number of table builders in the font builder.
+    virtual int32_t number_of_table_builders() {
+      return (int32_t)table_builders_.size();
+    }
+
+   private:
+    explicit Builder(FontFactory* factory);
+    virtual void LoadFont(InputStream* is);
+    virtual void LoadFont(WritableFontData* wfd,
+                          int32_t offset_to_offset_table);
+    int32_t SfntWrapperSize();
+    void BuildAllTableBuilders(DataBlockMap* table_data,
+                               TableBuilderMap* builder_map);
+    CALLER_ATTACH Table::Builder*
+        GetTableBuilder(Header* header, WritableFontData* data);
+    void BuildTablesFromBuilders(Font* font,
+                                 TableBuilderMap* builder_map,
+                                 TableMap* tables);
+    static void InterRelateBuilders(TableBuilderMap* builder_map);
+
+    void ReadHeader(FontInputStream* is,
+                    HeaderOffsetSortedSet* records);
+
+    void ReadHeader(ReadableFontData* fd,
+                    int32_t offset,
+                    HeaderOffsetSortedSet* records);
+
+    void LoadTableData(HeaderOffsetSortedSet* headers,
+                       FontInputStream* is,
+                       DataBlockMap* table_data);
+
+    void LoadTableData(HeaderOffsetSortedSet* headers,
+                       WritableFontData* fd,
+                       DataBlockMap* table_data);
+
+    TableBuilderMap table_builders_;
+    FontFactory* factory_;  // dumb pointer, avoid circular refcounting
+    int32_t sfnt_version_;
+    int32_t num_tables_;
+    int32_t search_range_;
+    int32_t entry_selector_;
+    int32_t range_shift_;
+    DataBlockMap data_blocks_;
+    ByteVector digest_;
+  };
+
+  virtual ~Font();
+
+  // Gets the sfnt version set in the sfnt wrapper of the font.
+  int32_t sfnt_version() { return sfnt_version_; }
+
+  // Gets a copy of the fonts digest that was created when the font was read. If
+  // no digest was set at creation time then the return result will be null.
+  ByteVector* digest() { return &digest_; }
+
+  // Get the checksum for this font.
+  int64_t checksum() { return checksum_; }
+
+  // Get the number of tables in this font.
+  int32_t num_tables() { return (int32_t)tables_.size(); }
+
+  // Whether the font has a particular table.
+  bool HasTable(int32_t tag);
+
+  // UNIMPLEMENTED: public Iterator<? extends Table> iterator
+
+  // Get the table in this font with the specified id.
+  // @param tag the identifier of the table
+  // @return the table specified if it exists; null otherwise
+  // C++ port: rename table() to GetTable()
+  Table* GetTable(int32_t tag);
+
+  // Get a map of the tables in this font accessed by table tag.
+  // @return an unmodifiable view of the tables in this font
+  // Note: renamed tableMap() to GetTableMap()
+  const TableMap* GetTableMap();
+
+  // UNIMPLEMENTED: toString()
+
+  // Serialize the font to the output stream.
+  // @param os the destination for the font serialization
+  // @param tableOrdering the table ordering to apply
+  void Serialize(OutputStream* os, IntegerList* table_ordering);
+
+ private:
+  // Offsets to specific elements in the underlying data. These offsets are
+  // relative to the start of the table or the start of sub-blocks within the
+  // table.
+  struct Offset {
+    enum {
+      // Offsets within the main directory
+      kSfntVersion = 0,
+      kNumTables = 4,
+      kSearchRange = 6,
+      kEntrySelector = 8,
+      kRangeShift = 10,
+      kTableRecordBegin = 12,
+      kSfntHeaderSize = 12,
+
+      // Offsets within a specific table record
+      kTableTag = 0,
+      kTableCheckSum = 4,
+      kTableOffset = 8,
+      kTableLength = 12,
+      kTableRecordSize = 16
+    };
+  };
+
+  // Note: the two constants are moved to tag.h to avoid VC++ bug.
+//  static const int32_t CFF_TABLE_ORDERING[];
+//  static const int32_t TRUE_TYPE_TABLE_ORDERING[];
+
+  // Constructor.
+  // @param sfntVersion the sfnt version
+  // @param digest the computed digest for the font; null if digest was not
+  //        computed
+  // Note: Current C++ port does not support SHA digest validation.
+  Font(int32_t sfnt_version, ByteVector* digest);
+
+  // Build the table headers to be used for serialization. These headers will be
+  // filled out with the data required for serialization. The headers will be
+  // sorted in the order specified and only those specified will have headers
+  // generated.
+  // @param tableOrdering the tables to generate headers for and the order to
+  //        sort them
+  // @return a list of table headers ready for serialization
+  void BuildTableHeadersForSerialization(IntegerList* table_ordering,
+                                         TableHeaderList* table_headers);
+
+  // Searialize the headers.
+  // @param fos the destination stream for the headers
+  // @param tableHeaders the headers to serialize
+  // @throws IOException
+  void SerializeHeader(FontOutputStream* fos, TableHeaderList* table_headers);
+
+  // Serialize the tables.
+  // @param fos the destination stream for the headers
+  // @param tableHeaders the headers for the tables to serialize
+  // @throws IOException
+  void SerializeTables(FontOutputStream* fos, TableHeaderList* table_headers);
+
+  // Generate the full table ordering to used for serialization. The full
+  // ordering uses the partial ordering as a seed and then adds all remaining
+  // tables in the font in an undefined order.
+  // @param defaultTableOrdering the partial ordering to be used as a seed for
+  //        the full ordering
+  // @param (out) table_ordering the full ordering for serialization
+  void GenerateTableOrdering(IntegerList* default_table_ordering,
+                             IntegerList* table_ordering);
+
+  // Get the default table ordering based on the type of the font.
+  // @param (out) default_table_ordering the default table ordering
+  void DefaultTableOrdering(IntegerList* default_table_ordering);
+
+  int32_t sfnt_version_;
+  ByteVector digest_;
+  int64_t checksum_;
+  TableMap tables_;
+};
+typedef Ptr<Font> FontPtr;
+typedef std::vector<FontPtr> FontArray;
+typedef Ptr<Font::Builder> FontBuilderPtr;
+typedef std::vector<FontBuilderPtr> FontBuilderArray;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_FONT_H_
diff --git a/cpp/src/sfntly/font_factory.cc b/cpp/src/sfntly/font_factory.cc
new file mode 100644
index 0000000..c162a77
--- /dev/null
+++ b/cpp/src/sfntly/font_factory.cc
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/font_factory.h"
+
+#include <string.h>
+
+#include "sfntly/tag.h"
+
+namespace sfntly {
+
+FontFactory::~FontFactory() {
+}
+
+CALLER_ATTACH FontFactory* FontFactory::GetInstance() {
+  FontFactoryPtr instance = new FontFactory();
+  return instance.Detach();
+}
+
+void FontFactory::FingerprintFont(bool fingerprint) {
+  fingerprint_ = fingerprint;
+}
+
+bool FontFactory::FingerprintFont() {
+  return fingerprint_;
+}
+
+void FontFactory::LoadFonts(InputStream* is, FontArray* output) {
+  assert(output);
+  PushbackInputStream* pbis = down_cast<PushbackInputStream*>(is);
+  if (IsCollection(pbis)) {
+    LoadCollection(pbis, output);
+    return;
+  }
+  FontPtr font;
+  font.Attach(LoadSingleOTF(pbis));
+  if (font) {
+    output->push_back(font);
+  }
+}
+
+void FontFactory::LoadFonts(ByteVector* b, FontArray* output) {
+  WritableFontDataPtr wfd;
+  wfd.Attach(WritableFontData::CreateWritableFontData(b));
+  if (IsCollection(wfd)) {
+    LoadCollection(wfd, output);
+    return;
+  }
+  FontPtr font;
+  font.Attach(LoadSingleOTF(wfd));
+  if (font) {
+    output->push_back(font);
+  }
+}
+
+void FontFactory::LoadFontsForBuilding(InputStream* is,
+                                       FontBuilderArray* output) {
+  PushbackInputStream* pbis = down_cast<PushbackInputStream*>(is);
+  if (IsCollection(pbis)) {
+    LoadCollectionForBuilding(pbis, output);
+    return;
+  }
+  FontBuilderPtr builder;
+  builder.Attach(LoadSingleOTFForBuilding(pbis));
+  if (builder) {
+    output->push_back(builder);
+  }
+}
+
+void FontFactory::LoadFontsForBuilding(ByteVector* b,
+                                       FontBuilderArray* output) {
+  WritableFontDataPtr wfd;
+  wfd.Attach(WritableFontData::CreateWritableFontData(b));
+  if (IsCollection(wfd)) {
+    LoadCollectionForBuilding(wfd, output);
+    return;
+  }
+  FontBuilderPtr builder;
+  builder.Attach(LoadSingleOTFForBuilding(wfd, 0));
+  if (builder) {
+    output->push_back(builder);
+  }
+}
+
+void FontFactory::SerializeFont(Font* font, OutputStream* os) {
+  font->Serialize(os, &table_ordering_);
+}
+
+void FontFactory::SetSerializationTableOrdering(
+    const IntegerList& table_ordering) {
+  table_ordering_ = table_ordering;
+}
+
+CALLER_ATTACH Font::Builder* FontFactory::NewFontBuilder() {
+  return Font::Builder::GetOTFBuilder(this);
+}
+
+CALLER_ATTACH Font* FontFactory::LoadSingleOTF(InputStream* is) {
+  FontBuilderPtr builder;
+  builder.Attach(LoadSingleOTFForBuilding(is));
+  return builder->Build();
+}
+
+CALLER_ATTACH Font* FontFactory::LoadSingleOTF(WritableFontData* wfd) {
+  FontBuilderPtr builder;
+  builder.Attach(LoadSingleOTFForBuilding(wfd, 0));
+  return builder->Build();
+}
+
+void FontFactory::LoadCollection(InputStream* is, FontArray* output) {
+  FontBuilderArray ba;
+  LoadCollectionForBuilding(is, &ba);
+  output->reserve(ba.size());
+  for (FontBuilderArray::iterator builder = ba.begin(), builders_end = ba.end();
+                                  builder != builders_end; ++builder) {
+      FontPtr font;
+      font.Attach((*builder)->Build());
+      output->push_back(font);
+  }
+}
+
+void FontFactory::LoadCollection(WritableFontData* wfd, FontArray* output) {
+  FontBuilderArray builders;
+  LoadCollectionForBuilding(wfd, &builders);
+  output->reserve(builders.size());
+  for (FontBuilderArray::iterator builder = builders.begin(),
+                                  builders_end = builders.end();
+                                  builder != builders_end; ++builder) {
+    FontPtr font;
+    font.Attach((*builder)->Build());
+    output->push_back(font);
+  }
+}
+
+CALLER_ATTACH
+Font::Builder* FontFactory::LoadSingleOTFForBuilding(InputStream* is) {
+  // UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream
+  Font::Builder* builder = Font::Builder::GetOTFBuilder(this, is);
+  // UNIMPLEMENTED: setDigest
+  return builder;
+}
+
+CALLER_ATTACH Font::Builder*
+    FontFactory::LoadSingleOTFForBuilding(WritableFontData* wfd,
+                                          int32_t offset_to_offset_table) {
+  // UNIMPLEMENTED: SHA-1 hash checking via Java DigestStream
+  Font::Builder* builder =
+      Font::Builder::GetOTFBuilder(this, wfd, offset_to_offset_table);
+  // UNIMPLEMENTED: setDigest
+  return builder;
+}
+
+void FontFactory::LoadCollectionForBuilding(InputStream* is,
+                                            FontBuilderArray* builders) {
+  assert(is);
+  assert(builders);
+  WritableFontDataPtr wfd;
+  wfd.Attach(WritableFontData::CreateWritableFontData(is->Available()));
+  wfd->CopyFrom(is);
+  LoadCollectionForBuilding(wfd, builders);
+}
+
+void FontFactory::LoadCollectionForBuilding(WritableFontData* wfd,
+                                            FontBuilderArray* builders) {
+  int32_t ttc_tag = wfd->ReadULongAsInt(Offset::kTTCTag);
+  UNREFERENCED_PARAMETER(ttc_tag);
+  int32_t version = wfd->ReadFixed(Offset::kVersion);
+  UNREFERENCED_PARAMETER(version);
+  int32_t num_fonts = wfd->ReadULongAsInt(Offset::kNumFonts);
+
+  builders->reserve(num_fonts);
+  int32_t offset_table_offset = Offset::kOffsetTable;
+  for (int32_t font_number = 0;
+               font_number < num_fonts;
+               font_number++, offset_table_offset += DataSize::kULONG) {
+    int32_t offset = wfd->ReadULongAsInt(offset_table_offset);
+    FontBuilderPtr builder;
+    builder.Attach(LoadSingleOTFForBuilding(wfd, offset));
+    builders->push_back(builder);
+  }
+}
+
+bool FontFactory::IsCollection(PushbackInputStream* pbis) {
+  ByteVector tag(4);
+  pbis->Read(&tag);
+  pbis->Unread(&tag);
+  return Tag::ttcf == GenerateTag(tag[0], tag[1], tag[2], tag[3]);
+}
+
+bool FontFactory::IsCollection(ReadableFontData* rfd) {
+  ByteVector tag(4);
+  rfd->ReadBytes(0, &(tag[0]), 0, tag.size());
+  return Tag::ttcf ==
+         GenerateTag(tag[0], tag[1], tag[2], tag[3]);
+}
+
+FontFactory::FontFactory()
+    : fingerprint_(false) {
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/font_factory.h b/cpp/src/sfntly/font_factory.h
new file mode 100644
index 0000000..63deff4
--- /dev/null
+++ b/cpp/src/sfntly/font_factory.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_
+#define SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_
+
+#include <vector>
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/port/type.h"
+#include "sfntly/font.h"
+
+namespace sfntly {
+
+class FontFactory : public RefCounted<FontFactory> {
+ public:
+  virtual ~FontFactory();
+
+  // Factory method for the construction of a font factory.
+  static CALLER_ATTACH FontFactory* GetInstance();
+
+  // Toggle whether fonts that are loaded are fingerprinted with a SHA-1 hash.
+  // If a font is fingerprinted then a SHA-1 hash is generated at load time and
+  // stored in the font. This is useful for uniquely identifying fonts. By
+  // default this is turned on.
+  // @param fingerprint whether fingerprinting should be turned on or off
+  // TODO(arthurhsu): IMPLEMENT: C++ port currently don't do any SHA-1
+  void FingerprintFont(bool fingerprint);
+  bool FingerprintFont();
+
+  // Load the font(s) from the input stream. The current settings on the factory
+  // are used during the loading process. One or more fonts are returned if the
+  // stream contains valid font data. Some font container formats may have more
+  // than one font and in this case multiple font objects will be returned. If
+  // the data in the stream cannot be parsed or is invalid an array of size zero
+  // will be returned.
+  void LoadFonts(InputStream* is, FontArray* output);
+
+  // ByteArray font loading
+  // Load the font(s) from the byte array. The current settings on the factory
+  // are used during the loading process. One or more fonts are returned if the
+  // stream contains valid font data. Some font container formats may have more
+  // than one font and in this case multiple font objects will be returned. If
+  // the data in the stream cannot be parsed or is invalid an array of size zero
+  // will be returned.
+  void LoadFonts(ByteVector* b, FontArray* output);
+
+  // Load the font(s) from the input stream into font builders. The current
+  // settings on the factory are used during the loading process. One or more
+  // font builders are returned if the stream contains valid font data. Some
+  // font container formats may have more than one font and in this case
+  // multiple font builder objects will be returned. If the data in the stream
+  // cannot be parsed or is invalid an array of size zero will be returned.
+  void LoadFontsForBuilding(InputStream* is, FontBuilderArray* output);
+
+  // Load the font(s) from the byte array into font builders. The current
+  // settings on the factory are used during the loading process. One or more
+  // font builders are returned if the stream contains valid font data. Some
+  // font container formats may have more than one font and in this case
+  // multiple font builder objects will be returned. If the data in the stream
+  // cannot be parsed or is invalid an array of size zero will be returned.
+  void LoadFontsForBuilding(ByteVector* b, FontBuilderArray* output);
+
+  // Font serialization
+  // Serialize the font to the output stream.
+  // NOTE: in this port we attempted not to implement I/O stream because dealing
+  //       with cross-platform I/O stream itself is big enough as a project.
+  //       Byte buffer it is.
+  void SerializeFont(Font* font, OutputStream* os);
+
+  // Set the table ordering to be used in serializing a font. The table ordering
+  // is an ordered list of table ids and tables will be serialized in the order
+  // given. Any tables whose id is not listed in the ordering will be placed in
+  // an unspecified order following those listed.
+  void SetSerializationTableOrdering(const IntegerList& table_ordering);
+
+  // Get an empty font builder for creating a new font from scratch.
+  CALLER_ATTACH Font::Builder* NewFontBuilder();
+
+ private:
+  // Offsets to specific elements in the underlying data. These offsets are
+  // relative to the start of the table or the start of sub-blocks within the
+  // table.
+  struct Offset {
+    enum {
+      // Offsets within the main directory.
+      kTTCTag = 0,
+      kVersion = 4,
+      kNumFonts = 8,
+      kOffsetTable = 12,
+
+      // TTC Version 2.0 extensions.
+      // Offsets from end of OffsetTable.
+      kulDsigTag = 0,
+      kulDsigLength = 4,
+      kulDsigOffset = 8
+    };
+  };
+
+  FontFactory();
+
+  CALLER_ATTACH Font* LoadSingleOTF(InputStream* is);
+  CALLER_ATTACH Font* LoadSingleOTF(WritableFontData* wfd);
+
+  void LoadCollection(InputStream* is, FontArray* output);
+  void LoadCollection(WritableFontData* wfd, FontArray* output);
+
+  CALLER_ATTACH Font::Builder* LoadSingleOTFForBuilding(InputStream* is);
+  CALLER_ATTACH Font::Builder*
+      LoadSingleOTFForBuilding(WritableFontData* wfd,
+                               int32_t offset_to_offset_table);
+
+  void LoadCollectionForBuilding(InputStream* is, FontBuilderArray* builders);
+  void LoadCollectionForBuilding(WritableFontData* ba,
+                                 FontBuilderArray* builders);
+
+  static bool IsCollection(PushbackInputStream* pbis);
+  static bool IsCollection(ReadableFontData* wfd);
+
+  bool fingerprint_;
+  IntegerList table_ordering_;
+};
+typedef Ptr<FontFactory> FontFactoryPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_FONT_FACTORY_H_
diff --git a/cpp/src/sfntly/math/fixed1616.h b/cpp/src/sfntly/math/fixed1616.h
new file mode 100644
index 0000000..4abbe18
--- /dev/null
+++ b/cpp/src/sfntly/math/fixed1616.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_
+#define SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+class Fixed1616 {
+ public:
+  static inline int32_t Integral(int32_t fixed) {
+    return (fixed >> 16);
+  }
+
+  static inline int32_t Fractional(int32_t fixed) {
+    return (fixed & 0xffff);
+  }
+
+  static inline int32_t Fixed(int32_t integral, int32_t fractional) {
+    return ((integral & 0xffff) << 16) | (fractional & 0xffff);
+  }
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_MATH_FIXED1616_H_
diff --git a/cpp/src/sfntly/math/font_math.h b/cpp/src/sfntly/math/font_math.h
new file mode 100644
index 0000000..f1cd2d2
--- /dev/null
+++ b/cpp/src/sfntly/math/font_math.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_
+#define SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+class FontMath {
+ public:
+  static int32_t Log2(int32_t a) {
+    int r = 0;  // r will be lg(a)
+    while (a != 0) {
+      a >>= 1;
+      r++;
+    }
+    return r - 1;
+  }
+
+  // Calculates the amount of padding needed. The values provided need to be in
+  // the same units. So, if the size is given as the number of bytes then the
+  // alignment size must also be specified as byte size to align to.
+  // @param size the size of the data that may need padding
+  // @param alignmentSize the number of units to align to
+  // @return the number of units needing to be added for alignment
+  static int32_t PaddingRequired(int32_t size, int32_t alignment_size) {
+    int32_t padding = alignment_size - (size % alignment_size);
+    return padding == alignment_size ? 0 : padding;
+  }
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_MATH_FONT_MATH_H_
diff --git a/cpp/src/sfntly/port/atomic.h b/cpp/src/sfntly/port/atomic.h
new file mode 100644
index 0000000..b381a52
--- /dev/null
+++ b/cpp/src/sfntly/port/atomic.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_
+
+#if defined (WIN32)
+
+#include <windows.h>
+
+static inline size_t AtomicIncrement(size_t* address) {
+#if defined (_WIN64)
+  return InterlockedIncrement64(reinterpret_cast<LONGLONG*>(address));
+#else
+  return InterlockedIncrement(reinterpret_cast<LONG*>(address));
+#endif
+}
+
+static inline size_t AtomicDecrement(size_t* address) {
+#if defined (_WIN64)
+  return InterlockedDecrement64(reinterpret_cast<LONGLONG*>(address));
+#else
+  return InterlockedDecrement(reinterpret_cast<LONG*>(address));
+#endif
+}
+
+#elif defined (__APPLE__)
+
+#include <libkern/OSAtomic.h>
+
+static inline size_t AtomicIncrement(size_t* address) {
+  return OSAtomicIncrement32Barrier(reinterpret_cast<int32_t*>(address));
+}
+
+static inline size_t AtomicDecrement(size_t* address) {
+  return OSAtomicDecrement32Barrier(reinterpret_cast<int32_t*>(address));
+}
+
+// Originally we check __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4, however, there are
+// issues that clang not carring over this definition.  Therefore we boldly
+// assume it's gcc or gcc-compatible here.  Compilation shall still fail since
+// the intrinsics used are GCC-specific.
+
+#else
+
+#include <stddef.h>
+
+static inline size_t AtomicIncrement(size_t* address) {
+  return __sync_add_and_fetch(address, 1);
+}
+
+static inline size_t AtomicDecrement(size_t* address) {
+  return __sync_sub_and_fetch(address, 1);
+}
+
+#endif  // WIN32
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_ATOMIC_H_
diff --git a/cpp/src/sfntly/port/config.h b/cpp/src/sfntly/port/config.h
new file mode 100644
index 0000000..0fcdffe
--- /dev/null
+++ b/cpp/src/sfntly/port/config.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_
+
+#if !defined(SFNTLY_BIG_ENDIAN) && !defined(SFNTLY_LITTLE_ENDIAN)
+  #if defined (__ppc__) || defined (__ppc64__)
+    #define SFNTLY_BIG_ENDIAN
+  #else
+    #define SFNTLY_LITTLE_ENDIAN
+  #endif
+#endif
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_CONFIG_H_
diff --git a/cpp/src/sfntly/port/endian.h b/cpp/src/sfntly/port/endian.h
new file mode 100644
index 0000000..db58f0a
--- /dev/null
+++ b/cpp/src/sfntly/port/endian.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_
+
+#include "sfntly/port/config.h"
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+static inline uint16_t EndianSwap16(uint16_t value) {
+  return (uint16_t)((value >> 8) | (value << 8));
+}
+
+static inline int32_t EndianSwap32(int32_t value) {
+  return (((value & 0x000000ff) << 24) |
+          ((value & 0x0000ff00) <<  8) |
+          ((value & 0x00ff0000) >>  8) |
+          ((value & 0xff000000) >> 24));
+}
+
+static inline uint64_t EndianSwap64(uint64_t value) {
+  return (((value & 0x00000000000000ffLL) << 56) |
+          ((value & 0x000000000000ff00LL) << 40) |
+          ((value & 0x0000000000ff0000LL) << 24) |
+          ((value & 0x00000000ff000000LL) << 8)  |
+          ((value & 0x000000ff00000000LL) >> 8)  |
+          ((value & 0x0000ff0000000000LL) >> 24) |
+          ((value & 0x00ff000000000000LL) >> 40) |
+          ((value & 0xff00000000000000LL) >> 56));
+}
+
+#ifdef SFNTLY_LITTLE_ENDIAN
+  #define ToBE16(n) EndianSwap16(n)
+  #define ToBE32(n) EndianSwap32(n)
+  #define ToBE64(n) EndianSwap64(n)
+  #define ToLE16(n) (n)
+  #define ToLE32(n) (n)
+  #define ToLE64(n) (n)
+  #define FromBE16(n) EndianSwap16(n)
+  #define FromBE32(n) EndianSwap32(n)
+  #define FromBE64(n) EndianSwap64(n)
+  #define FromLE16(n) (n)
+  #define FromLE32(n) (n)
+  #define FromLE64(n) (n)
+#else  // SFNTLY_BIG_ENDIAN
+  #define ToBE16(n) (n)
+  #define ToBE32(n) (n)
+  #define ToBE64(n) (n)
+  #define ToLE16(n) EndianSwap16(n)
+  #define ToLE32(n) EndianSwap32(n)
+  #define ToLE64(n) EndianSwap64(n)
+  #define FromBE16(n) (n)
+  #define FromBE32(n) (n)
+  #define FromBE64(n) (n)
+  #define FromLE16(n) EndianSwap16(n)
+  #define FromLE32(n) EndianSwap32(n)
+  #define FromLE64(n) EndianSwap64(n)
+#endif
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_ENDIAN_H_
diff --git a/cpp/src/sfntly/port/exception_type.h b/cpp/src/sfntly/port/exception_type.h
new file mode 100644
index 0000000..b96efcb
--- /dev/null
+++ b/cpp/src/sfntly/port/exception_type.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Exceptions used in sfntly
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_
+
+#if !defined (SFNTLY_NO_EXCEPTION)
+
+#include <exception>
+#include <string>
+#include <sstream>
+
+namespace sfntly {
+
+class Exception : public std::exception {
+ public:
+  Exception() : what_("Unknown exception") {}
+  explicit Exception(const char* message) throw() { SetMessage(message); }
+  virtual ~Exception() throw() {}
+  virtual const char* what() const throw() { return what_.c_str(); }
+
+ protected:
+  void SetMessage(const char* message) throw() {
+    try {
+      what_ = message;
+    } catch (...) {}
+  }
+
+ private:
+  std::string what_;
+};
+
+class IndexOutOfBoundException : public Exception {
+ public:
+  IndexOutOfBoundException() throw() : Exception("Index out of bound") {}
+  explicit IndexOutOfBoundException(const char* message) throw()
+      : Exception(message) {}
+  IndexOutOfBoundException(const char* message, int32_t index) throw() {
+    try {
+      std::ostringstream msg;
+      msg << message;
+      msg << ":";
+      msg << index;
+      SetMessage(msg.str().c_str());
+    } catch (...) {}
+  }
+  virtual ~IndexOutOfBoundException() throw() {}
+};
+
+class IOException : public Exception {
+ public:
+  IOException() throw() : Exception("I/O exception") {}
+  explicit IOException(const char* message) throw() : Exception(message) {}
+  virtual ~IOException() throw() {}
+};
+
+class ArithmeticException : public Exception {
+ public:
+  ArithmeticException() throw() : Exception("Arithmetic exception") {}
+  explicit ArithmeticException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~ArithmeticException() throw() {}
+};
+
+class UnsupportedOperationException : public Exception {
+ public:
+  UnsupportedOperationException() throw() :
+      Exception("Operation not supported") {}
+  explicit UnsupportedOperationException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~UnsupportedOperationException() throw() {}
+};
+
+class RuntimeException : public Exception {
+ public:
+  RuntimeException() throw() : Exception("Runtime exception") {}
+  explicit RuntimeException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~RuntimeException() throw() {}
+};
+
+class NoSuchElementException : public Exception {
+ public:
+  NoSuchElementException() throw() : Exception("No such element") {}
+  explicit NoSuchElementException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~NoSuchElementException() throw() {}
+};
+
+class IllegalArgumentException : public Exception {
+ public:
+  IllegalArgumentException() throw() : Exception("Illegal argument") {}
+  explicit IllegalArgumentException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~IllegalArgumentException() throw() {}
+};
+
+class IllegalStateException : public Exception {
+ public:
+  IllegalStateException() throw() : Exception("Illegal state") {}
+  explicit IllegalStateException(const char* message) throw()
+      : Exception(message) {}
+  virtual ~IllegalStateException() throw() {}
+};
+
+}  // namespace sfntly
+
+#endif  // #if !defined (SFNTLY_NO_EXCEPTION)
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_EXCEPTION_TYPE_H_
diff --git a/cpp/src/sfntly/port/file_input_stream.cc b/cpp/src/sfntly/port/file_input_stream.cc
new file mode 100644
index 0000000..5bcb434
--- /dev/null
+++ b/cpp/src/sfntly/port/file_input_stream.cc
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined (WIN32)
+#include <windows.h>
+#endif
+
+#include "sfntly/port/file_input_stream.h"
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+
+FileInputStream::FileInputStream()
+    : file_(NULL),
+      position_(0),
+      length_(0) {
+}
+
+FileInputStream::~FileInputStream() {
+  Close();
+}
+
+int32_t FileInputStream::Available() {
+  return length_ - position_;
+}
+
+void FileInputStream::Close() {
+  if (file_) {
+    fclose(file_);
+    length_ = 0;
+    position_ = 0;
+    file_ = NULL;
+  }
+}
+
+void FileInputStream::Mark(int32_t readlimit) {
+  // NOP
+  UNREFERENCED_PARAMETER(readlimit);
+}
+
+bool FileInputStream::MarkSupported() {
+  return false;
+}
+
+int32_t FileInputStream::Read() {
+  if (!file_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no opened file");
+#endif
+    return 0;
+  }
+  if (feof(file_)) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("eof reached");
+#endif
+    return 0;
+  }
+  byte_t value;
+  size_t length = fread(&value, 1, 1, file_);
+  position_ += length;
+  return value;
+}
+
+int32_t FileInputStream::Read(ByteVector* b) {
+  return Read(b, 0, b->size());
+}
+
+int32_t FileInputStream::Read(ByteVector* b, int32_t offset, int32_t length) {
+  assert(b);
+  if (!file_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no opened file");
+#endif
+    return 0;
+  }
+  if (feof(file_)) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("eof reached");
+#endif
+    return 0;
+  }
+  size_t read_count = std::min<size_t>(length_ - position_, length);
+  if (b->size() < (size_t)(offset + read_count)) {
+    b->resize((size_t)(offset + read_count));
+  }
+  int32_t actual_read = fread(&((*b)[offset]), 1, read_count, file_);
+  position_ += actual_read;
+  return actual_read;
+}
+
+void FileInputStream::Reset() {
+  // NOP
+}
+
+int64_t FileInputStream::Skip(int64_t n) {
+  if (!file_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no opened file");
+#endif
+    return 0;
+  }
+  int64_t skip_count = 0;
+  if (n < 0) {  // move backwards
+    skip_count = std::max<int64_t>(0 - (int64_t)position_, n);
+    position_ -= (size_t)(0 - skip_count);
+    fseek(file_, position_, SEEK_SET);
+  } else {
+    skip_count = std::min<size_t>(length_ - position_, (size_t)n);
+    position_ += (size_t)skip_count;
+    fseek(file_, (size_t)skip_count, SEEK_CUR);
+  }
+  return skip_count;
+}
+
+void FileInputStream::Unread(ByteVector* b) {
+  Unread(b, 0, b->size());
+}
+
+void FileInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) {
+  assert(b);
+  assert(b->size() >= size_t(offset + length));
+  if (!file_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no opened file");
+#endif
+    return;
+  }
+  size_t unread_count = std::min<size_t>(position_, length);
+  fseek(file_, position_ - unread_count, SEEK_SET);
+  position_ -= unread_count;
+  Read(b, offset, length);
+  fseek(file_, position_ - unread_count, SEEK_SET);
+  position_ -= unread_count;
+}
+
+bool FileInputStream::Open(const char* file_path) {
+  assert(file_path);
+  if (file_) {
+    Close();
+  }
+#if defined (WIN32)
+  fopen_s(&file_, file_path, "rb");
+#else
+  file_ = fopen(file_path, "rb");
+#endif
+  if (file_ == NULL) {
+    return false;
+  }
+
+  fseek(file_, 0, SEEK_END);
+  length_ = ftell(file_);
+  fseek(file_, 0, SEEK_SET);
+  return true;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/port/file_input_stream.h b/cpp/src/sfntly/port/file_input_stream.h
new file mode 100644
index 0000000..cbca25f
--- /dev/null
+++ b/cpp/src/sfntly/port/file_input_stream.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_
+
+#include <stdio.h>
+
+#include "sfntly/port/input_stream.h"
+
+namespace sfntly {
+
+class FileInputStream : public PushbackInputStream {
+ public:
+  FileInputStream();
+  virtual ~FileInputStream();
+
+  // InputStream methods
+  virtual int32_t Available();
+  virtual void Close();
+  virtual void Mark(int32_t readlimit);
+  virtual bool MarkSupported();
+  virtual int32_t Read();
+  virtual int32_t Read(ByteVector* b);
+  virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length);
+  virtual void Reset();
+  virtual int64_t Skip(int64_t n);
+
+  // PushbackInputStream methods
+  virtual void Unread(ByteVector* b);
+  virtual void Unread(ByteVector* b, int32_t offset, int32_t length);
+
+  // Own methods
+  virtual bool Open(const char* file_path);
+
+ private:
+  FILE* file_;
+  size_t position_;
+  size_t length_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_FILE_INPUT_STREAM_H_
diff --git a/cpp/src/sfntly/port/input_stream.h b/cpp/src/sfntly/port/input_stream.h
new file mode 100644
index 0000000..5d24036
--- /dev/null
+++ b/cpp/src/sfntly/port/input_stream.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+// C++ equivalent to Java's OutputStream class
+class InputStream {
+ public:
+  // Make gcc -Wnon-virtual-dtor happy.
+  virtual ~InputStream() {}
+
+  virtual int32_t Available() = 0;
+  virtual void Close() = 0;
+  virtual void Mark(int32_t readlimit) = 0;
+  virtual bool MarkSupported() = 0;
+  virtual int32_t Read() = 0;
+  virtual int32_t Read(ByteVector* b) = 0;
+  virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length) = 0;
+  virtual void Reset() = 0;
+  virtual int64_t Skip(int64_t n) = 0;
+};
+
+class PushbackInputStream : public InputStream {
+ public:
+  virtual void Unread(ByteVector* b) = 0;
+  virtual void Unread(ByteVector* b, int32_t offset, int32_t length) = 0;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_INPUT_STREAM_H_
diff --git a/cpp/src/sfntly/port/java_iterator.h b/cpp/src/sfntly/port/java_iterator.h
new file mode 100644
index 0000000..0a99bca
--- /dev/null
+++ b/cpp/src/sfntly/port/java_iterator.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_
+
+#include "sfntly/port/refcount.h"
+
+// Interface of Java iterator.
+// This is a forward read-only iterator that represents java.util.Iterator<E>
+
+namespace sfntly {
+
+template <typename ReturnType, typename ContainerBase>
+class Iterator : public virtual RefCount {
+ public:
+  virtual ~Iterator() {}
+  virtual ContainerBase* container_base() = 0;
+
+ protected:
+  Iterator() {}
+  NO_COPY_AND_ASSIGN(Iterator);
+};
+
+template <typename ReturnType, typename Container,
+          typename ContainerBase = Container>
+class PODIterator : public Iterator<ReturnType, ContainerBase>,
+                    public RefCounted< PODIterator<ReturnType, Container> > {
+ public:
+  explicit PODIterator(Container* container) : container_(container) {}
+  virtual ~PODIterator() {}
+  virtual ContainerBase* container_base() {
+    return static_cast<ContainerBase*>(container_);
+  }
+
+  virtual bool HasNext() = 0;
+  virtual ReturnType Next() = 0;
+  virtual void Remove() {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    // Default to no support.
+    throw UnsupportedOperationException();
+#endif
+  }
+
+ protected:
+  Container* container() { return container_; }
+
+ private:
+  Container* container_;  // Dumb pointer is used to avoid circular ref-counting
+};
+
+template <typename ReturnType, typename Container,
+          typename ContainerBase = Container>
+class RefIterator : public Iterator<ReturnType, ContainerBase>,
+                    public RefCounted< RefIterator<ReturnType, Container> > {
+ public:
+  explicit RefIterator(Container* container) : container_(container) {}
+  virtual ~RefIterator() {}
+  virtual ContainerBase* container_base() {
+    return static_cast<ContainerBase*>(container_);
+  }
+
+  virtual bool HasNext() = 0;
+  CALLER_ATTACH virtual ReturnType* Next() = 0;
+  virtual void Remove() {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    // Default to no support.
+    throw UnsupportedOperationException();
+#endif
+  }
+
+ protected:
+  Container* container() { return container_; }
+
+ private:
+  Container* container_;  // Dumb pointer is used to avoid circular ref-counting
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_JAVA_ITERATOR_H_
diff --git a/cpp/src/sfntly/port/lock.cc b/cpp/src/sfntly/port/lock.cc
new file mode 100644
index 0000000..6c0c309
--- /dev/null
+++ b/cpp/src/sfntly/port/lock.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/port/lock.h"
+
+namespace sfntly {
+
+#if defined (WIN32)
+
+Lock::Lock() {
+  // The second parameter is the spin count, for short-held locks it avoid the
+  // contending thread from going to sleep which helps performance greatly.
+  ::InitializeCriticalSectionAndSpinCount(&os_lock_, 2000);
+}
+
+Lock::~Lock() {
+  ::DeleteCriticalSection(&os_lock_);
+}
+
+bool Lock::Try() {
+  if (::TryEnterCriticalSection(&os_lock_) != FALSE) {
+    return true;
+  }
+  return false;
+}
+
+void Lock::Acquire() {
+  ::EnterCriticalSection(&os_lock_);
+}
+
+void Lock::Unlock() {
+  ::LeaveCriticalSection(&os_lock_);
+}
+
+#else  // We assume it's pthread
+
+Lock::Lock() {
+  pthread_mutex_init(&os_lock_, NULL);
+}
+
+Lock::~Lock() {
+  pthread_mutex_destroy(&os_lock_);
+}
+
+bool Lock::Try() {
+  return (pthread_mutex_trylock(&os_lock_) == 0);
+}
+
+void Lock::Acquire() {
+  pthread_mutex_lock(&os_lock_);
+}
+
+void Lock::Unlock() {
+  pthread_mutex_unlock(&os_lock_);
+}
+
+#endif
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/port/lock.h b/cpp/src/sfntly/port/lock.h
new file mode 100644
index 0000000..b2e29bf
--- /dev/null
+++ b/cpp/src/sfntly/port/lock.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_
+
+#if defined (WIN32)
+#include <windows.h>
+#else  // Assume pthread.
+#include <pthread.h>
+#include <errno.h>
+#endif
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+#if defined (WIN32)
+  typedef CRITICAL_SECTION OSLockType;
+#else  // Assume pthread.
+  typedef pthread_mutex_t OSLockType;
+#endif
+
+class Lock {
+ public:
+  Lock();
+  ~Lock();
+
+  // If the lock is not held, take it and return true.  If the lock is already
+  // held by something else, immediately return false.
+  bool Try();
+
+  // Take the lock, blocking until it is available if necessary.
+  void Acquire();
+
+  // Release the lock.  This must only be called by the lock's holder: after
+  // a successful call to Try, or a call to Lock.
+  void Unlock();
+
+ private:
+  OSLockType os_lock_;
+  NO_COPY_AND_ASSIGN(Lock);
+};
+
+// A helper class that acquires the given Lock while the AutoLock is in scope.
+class AutoLock {
+ public:
+  explicit AutoLock(Lock& lock) : lock_(lock) {
+    lock_.Acquire();
+  }
+
+  ~AutoLock() {
+    lock_.Unlock();
+  }
+
+ private:
+  Lock& lock_;
+  NO_COPY_AND_ASSIGN(AutoLock);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_LOCK_H_
diff --git a/cpp/src/sfntly/port/memory_input_stream.cc b/cpp/src/sfntly/port/memory_input_stream.cc
new file mode 100755
index 0000000..56ee81e
--- /dev/null
+++ b/cpp/src/sfntly/port/memory_input_stream.cc
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if defined (WIN32)
+#include <windows.h>
+#endif
+
+#include <string.h>
+
+#include "sfntly/port/memory_input_stream.h"
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+
+MemoryInputStream::MemoryInputStream()
+    : buffer_(NULL),
+      position_(0),
+      length_(0) {
+}
+
+MemoryInputStream::~MemoryInputStream() {
+  Close();
+}
+
+int32_t MemoryInputStream::Available() {
+  return length_ - position_;
+}
+
+void MemoryInputStream::Close() {
+}
+
+void MemoryInputStream::Mark(int32_t readlimit) {
+  // NOP
+  UNREFERENCED_PARAMETER(readlimit);
+}
+
+bool MemoryInputStream::MarkSupported() {
+  return false;
+}
+
+int32_t MemoryInputStream::Read() {
+  if (!buffer_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no memory attached");
+#endif
+    return 0;
+  }
+  if (position_ >= length_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("eof reached");
+#endif
+    return 0;
+  }
+  byte_t value = buffer_[position_++];
+  return value;
+}
+
+int32_t MemoryInputStream::Read(ByteVector* b) {
+  return Read(b, 0, b->size());
+}
+
+int32_t MemoryInputStream::Read(ByteVector* b, int32_t offset, int32_t length) {
+  assert(b);
+  if (!buffer_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no memory attached");
+#endif
+    return 0;
+  }
+  if (position_ >= length_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("eof reached");
+#endif
+    return 0;
+  }
+  size_t read_count = std::min<size_t>(length_ - position_, length);
+  if (b->size() < (size_t)(offset + read_count)) {
+    b->resize((size_t)(offset + read_count));
+  }
+  memcpy(&((*b)[offset]), buffer_ + position_, read_count);
+  position_ += read_count;
+  return read_count;
+}
+
+void MemoryInputStream::Reset() {
+  // NOP
+}
+
+int64_t MemoryInputStream::Skip(int64_t n) {
+  if (!buffer_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no memory attached");
+#endif
+    return 0;
+  }
+  int64_t skip_count = 0;
+  if (n < 0) {  // move backwards
+    skip_count = std::max<int64_t>(0 - (int64_t)position_, n);
+    position_ -= (size_t)(0 - skip_count);
+  } else {
+    skip_count = std::min<size_t>(length_ - position_, (size_t)n);
+    position_ += (size_t)skip_count;
+  }
+  return skip_count;
+}
+
+void MemoryInputStream::Unread(ByteVector* b) {
+  Unread(b, 0, b->size());
+}
+
+void MemoryInputStream::Unread(ByteVector* b, int32_t offset, int32_t length) {
+  assert(b);
+  assert(b->size() >= size_t(offset + length));
+  if (!buffer_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("no memory attached");
+#endif
+    return;
+  }
+  size_t unread_count = std::min<size_t>(position_, length);
+  position_ -= unread_count;
+  Read(b, offset, length);
+  position_ -= unread_count;
+}
+
+bool MemoryInputStream::Attach(const byte_t* buffer, size_t length) {
+  assert(buffer);
+  assert(length);
+  buffer_ = buffer;
+  length_ = length;
+  return true;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/port/memory_input_stream.h b/cpp/src/sfntly/port/memory_input_stream.h
new file mode 100755
index 0000000..bc861c3
--- /dev/null
+++ b/cpp/src/sfntly/port/memory_input_stream.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_
+
+#include <stdio.h>
+
+#include "sfntly/port/input_stream.h"
+
+namespace sfntly {
+
+class MemoryInputStream : public PushbackInputStream {
+ public:
+  MemoryInputStream();
+  virtual ~MemoryInputStream();
+
+  // InputStream methods
+  virtual int32_t Available();
+  virtual void Close();
+  virtual void Mark(int32_t readlimit);
+  virtual bool MarkSupported();
+  virtual int32_t Read();
+  virtual int32_t Read(ByteVector* b);
+  virtual int32_t Read(ByteVector* b, int32_t offset, int32_t length);
+  virtual void Reset();
+  virtual int64_t Skip(int64_t n);
+
+  // PushbackInputStream methods
+  virtual void Unread(ByteVector* b);
+  virtual void Unread(ByteVector* b, int32_t offset, int32_t length);
+
+  // Own methods
+  virtual bool Attach(const byte_t* buffer, size_t length);
+
+ private:
+  const byte_t* buffer_;
+  size_t position_;
+  size_t length_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_INPUT_STREAM_H_
diff --git a/cpp/src/sfntly/port/memory_output_stream.cc b/cpp/src/sfntly/port/memory_output_stream.cc
new file mode 100644
index 0000000..f2ff2e3
--- /dev/null
+++ b/cpp/src/sfntly/port/memory_output_stream.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/port/memory_output_stream.h"
+
+namespace sfntly {
+
+MemoryOutputStream::MemoryOutputStream() {
+}
+
+MemoryOutputStream::~MemoryOutputStream() {
+}
+
+void MemoryOutputStream::Write(ByteVector* buffer) {
+  store_.insert(store_.end(), buffer->begin(), buffer->end());
+}
+
+void MemoryOutputStream::Write(ByteVector* buffer,
+                               int32_t offset,
+                               int32_t length) {
+  assert(buffer);
+  if (offset >= 0 && length > 0) {
+    store_.insert(store_.end(),
+                  buffer->begin() + offset,
+                  buffer->begin() + offset + length);
+  } else {
+#if !defined(SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#endif
+  }
+}
+
+void MemoryOutputStream::Write(byte_t* buffer, int32_t offset, int32_t length) {
+  assert(buffer);
+  if (offset >= 0 && length > 0) {
+    store_.insert(store_.end(), buffer + offset, buffer + offset + length);
+  } else {
+#if !defined(SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#endif
+  }
+}
+
+void MemoryOutputStream::Write(byte_t b) {
+  store_.push_back(b);
+}
+
+byte_t* MemoryOutputStream::Get() {
+  if (store_.empty()) {
+    return NULL;
+  }
+  return &(store_[0]);
+}
+
+size_t MemoryOutputStream::Size() {
+  return store_.size();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/port/memory_output_stream.h b/cpp/src/sfntly/port/memory_output_stream.h
new file mode 100644
index 0000000..d1eda7f
--- /dev/null
+++ b/cpp/src/sfntly/port/memory_output_stream.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_
+
+#include <cstddef>
+#include <vector>
+
+#include "sfntly/port/type.h"
+#include "sfntly/port/output_stream.h"
+
+namespace sfntly {
+
+// OutputStream backed by STL vector
+
+class MemoryOutputStream : public OutputStream {
+ public:
+  MemoryOutputStream();
+  virtual ~MemoryOutputStream();
+
+  virtual void Close() {}  // no-op
+  virtual void Flush() {}  // no-op
+  virtual void Write(ByteVector* buffer);
+  virtual void Write(ByteVector* buffer, int32_t offset, int32_t length);
+  virtual void Write(byte_t* buffer, int32_t offset, int32_t length);
+  virtual void Write(byte_t b);
+
+  byte_t* Get();
+  size_t Size();
+
+ private:
+  std::vector<byte_t> store_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_MEMORY_OUTPUT_STREAM_H_
diff --git a/cpp/src/sfntly/port/output_stream.h b/cpp/src/sfntly/port/output_stream.h
new file mode 100644
index 0000000..64a6024
--- /dev/null
+++ b/cpp/src/sfntly/port/output_stream.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+// C++ equivalent to Java's OutputStream class
+class OutputStream {
+ public:
+  // Make gcc -Wnon-virtual-dtor happy.
+  virtual ~OutputStream() {}
+
+  virtual void Close() = 0;
+  virtual void Flush() = 0;
+  virtual void Write(ByteVector* buffer) = 0;
+  virtual void Write(byte_t b) = 0;
+
+  // Note: C++ port offered both versions of Write() here.  The first one is
+  //       better because it does check bounds.  The second one is there for
+  //       performance concerns.
+  virtual void Write(ByteVector* buffer, int32_t offset, int32_t length) = 0;
+
+  // Note: Caller is responsible for the boundary of buffer.
+  virtual void Write(byte_t* buffer, int32_t offset, int32_t length) = 0;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_OUTPUT_STREAM_H_
diff --git a/cpp/src/sfntly/port/refcount.h b/cpp/src/sfntly/port/refcount.h
new file mode 100644
index 0000000..eed5162
--- /dev/null
+++ b/cpp/src/sfntly/port/refcount.h
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Object reference count and smart pointer implementation.
+
+// Smart pointer usage in sfntly:
+//
+// sfntly carries a smart pointer implementation like COM.  Ref-countable object
+// type inherits from RefCounted<>, which have AddRef and Release just like
+// IUnknown (but no QueryInterface).  Use a Ptr<> based smart pointer to hold
+// the object so that the object ref count is handled correctly.
+//
+// class Foo : public RefCounted<Foo> {
+//  public:
+//   static Foo* CreateInstance() {
+//     Ptr<Foo> obj = new Foo();  // ref count = 1
+//     return obj.Detach();
+//   }
+// };
+// typedef Ptr<Foo> FooPtr;  // common short-hand notation
+// FooPtr obj;
+// obj.Attach(Foo::CreatedInstance());  // ref count = 1
+// {
+//   FooPtr obj2 = obj;  // ref count = 2
+// }  // ref count = 1, obj2 out of scope
+// obj.Release();  // ref count = 0, object destroyed
+
+// Notes on usage:
+// 1. Virtual inherit from RefCount interface in base class if smart pointers
+//    are going to be defined.
+// 2. All RefCounted objects must be instantiated on the heap.  Allocating the
+//    object on stack will cause crash.
+// 3. Be careful when you have complex inheritance.  For example,
+//    class A : public RefCounted<A>;
+//    class B : public A, public RefCounted<B>;
+//    In this case the smart pointer is pretty dumb and don't count on it to
+//    nicely destroy your objects as designed. Try refactor your code like
+//    class I;  // the common interface and implementations
+//    class A : public I, public RefCounted<A>;  // A specific implementation
+//    class B : public I, public RefCounted<B>;  // B specific implementation
+// 4. Smart pointers here are very bad candidates for function parameters.  Use
+//    dumb pointers in function parameter list.
+// 5. When down_cast is performed on a dangling pointer due to bugs in code,
+//    VC++ will generate SEH which is not handled well in VC++ debugger.  One
+//    can use WinDBG to run it and get the faulting stack.
+// 6. Idioms for heap object as return value
+//    Foo* createFoo() { FooPtr obj = new Foo(); return obj.Detach(); }
+//    Foo* passthru() { FooPtr obj = createFoo(), return obj; }
+//    FooPtr end_scope_pointer;
+//    end_scope_pointer.Attach(passThrough);
+//    If you are not passing that object back, you are the end of scope.
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_
+
+#if !defined (NDEBUG)
+  #define ENABLE_OBJECT_COUNTER
+//  #define REF_COUNT_DEBUGGING
+#endif
+
+#if defined (REF_COUNT_DEBUGGING)
+  #include <stdio.h>
+  #include <typeinfo>
+#endif
+
+#include "sfntly/port/atomic.h"
+#include "sfntly/port/type.h"
+
+// Special tag for functions that requires caller to attach instead of using
+// assignment operators.
+#define CALLER_ATTACH
+
+#if defined (REF_COUNT_DEBUGGING)
+  #define DEBUG_OUTPUT(a) \
+      fprintf(stderr, "%s%s:oc=%d,oid=%d,rc=%d\n", a, \
+              typeid(this).name(), object_counter_, object_id_, ref_count_)
+#else
+  #define DEBUG_OUTPUT(a)
+#endif
+
+#if defined (_MSC_VER)
+  // VC 2008/2010 incorrectly gives this warning for pure virtual functions
+  // in virtual inheritance.  The only way to get around it is to disable it.
+  #pragma warning(disable:4250)
+#endif
+
+namespace sfntly {
+
+class RefCount {
+ public:
+  // Make gcc -Wnon-virtual-dtor happy.
+  virtual ~RefCount() {}
+
+  virtual size_t AddRef() const = 0;
+  virtual size_t Release() const = 0;
+};
+
+template <typename T>
+class NoAddRefRelease : public T {
+ public:
+  NoAddRefRelease();
+  ~NoAddRefRelease();
+
+ private:
+  virtual size_t AddRef() const = 0;
+  virtual size_t Release() const = 0;
+};
+
+template <typename TDerived>
+class RefCounted : virtual public RefCount {
+ public:
+  RefCounted() : ref_count_(0) {
+#if defined (ENABLE_OBJECT_COUNTER)
+    object_id_ = AtomicIncrement(&next_id_);
+    AtomicIncrement(&object_counter_);
+    DEBUG_OUTPUT("C ");
+#endif
+  }
+  RefCounted(const RefCounted<TDerived>&) : ref_count_(0) {}
+  virtual ~RefCounted() {
+#if defined (ENABLE_OBJECT_COUNTER)
+    AtomicDecrement(&object_counter_);
+    DEBUG_OUTPUT("D ");
+#endif
+  }
+
+  RefCounted<TDerived>& operator=(const RefCounted<TDerived>&) {
+    // Each object maintains own ref count, don't propagate.
+    return *this;
+  }
+
+  virtual size_t AddRef() const {
+    size_t new_count = AtomicIncrement(&ref_count_);
+    DEBUG_OUTPUT("A ");
+    return new_count;
+  }
+
+  virtual size_t Release() const {
+    size_t new_ref_count = AtomicDecrement(&ref_count_);
+    DEBUG_OUTPUT("R ");
+    if (new_ref_count == 0) {
+      // A C-style is used to cast away const-ness and to derived.
+      // lint does not like this but this is how it works.
+      delete (TDerived*)(this);
+    }
+    return new_ref_count;
+  }
+
+  mutable size_t ref_count_;  // reference count of current object
+#if defined (ENABLE_OBJECT_COUNTER)
+  static size_t object_counter_;
+  static size_t next_id_;
+  mutable size_t object_id_;
+#endif
+};
+
+#if defined (ENABLE_OBJECT_COUNTER)
+template <typename TDerived> size_t RefCounted<TDerived>::object_counter_ = 0;
+template <typename TDerived> size_t RefCounted<TDerived>::next_id_ = 0;
+#endif
+
+// semi-smart pointer for RefCount derived objects, similar to CComPtr
+template <typename T>
+class Ptr {
+ public:
+  Ptr() : p_(NULL) {
+  }
+
+  // This constructor shall not be explicit.
+  // lint does not like this but this is how it works.
+  Ptr(T* pT) : p_(NULL) {
+    *this = pT;
+  }
+
+  Ptr(const Ptr<T>& p) : p_(NULL) {
+    *this = p;
+  }
+
+  ~Ptr() {
+    Release();
+  }
+
+  T* operator=(T* pT) {
+    if (p_ == pT) {
+      return p_;
+    }
+    if (pT) {
+      RefCount* p = static_cast<RefCount*>(pT);
+      if (p == NULL) {
+        return NULL;
+      }
+      p->AddRef();  // always AddRef() before Release()
+    }
+    Release();
+    p_ = pT;
+    return p_;
+  }
+
+  T* operator=(const Ptr<T>& p) {
+    if (p_ == p.p_) {
+      return p_;
+    }
+    return operator=(p.p_);
+  }
+
+  operator T*&() {
+    return p_;
+  }
+
+  T& operator*() const {
+    return *p_;  // It can throw!
+  }
+
+  NoAddRefRelease<T>* operator->() const {
+    return (NoAddRefRelease<T>*)p_;  // It can throw!
+  }
+
+  bool operator!() const {
+    return (p_ == NULL);
+  }
+
+  bool operator<(const Ptr<T>& p) const {
+    return (p_ < p.p_);
+  }
+
+  bool operator!=(T* pT) const {
+    return !operator==(pT);
+  }
+
+  bool operator==(T* pT) const {
+    return (p_ == pT);
+  }
+
+  size_t Release() const {
+    size_t ref_count = 0;
+    if (p_) {
+      RefCount* p = static_cast<RefCount*>(p_);
+      if (p) {
+        ref_count = p->Release();
+      }
+      p_ = NULL;
+    }
+    return ref_count;
+  }
+
+  void Attach(T* pT) {
+    if (p_ != pT) {
+      Release();
+      p_ = pT;
+    }
+  }
+
+  T* Detach() {
+    T* pT = p_;
+    p_ = NULL;
+    return pT;
+  }
+
+  mutable T* p_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_
diff --git a/cpp/src/sfntly/port/type.h b/cpp/src/sfntly/port/type.h
new file mode 100644
index 0000000..20a5ba8
--- /dev/null
+++ b/cpp/src/sfntly/port/type.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_
+
+#include <assert.h>
+
+#if defined (_MSC_VER) && (_MSC_VER < 1600)
+  typedef unsigned char     uint8_t;
+  typedef signed char       int8_t;
+  typedef unsigned __int16  uint16_t;
+  typedef signed __int16    int16_t;
+  typedef unsigned __int32  uint32_t;
+  typedef signed __int32    int32_t;
+  typedef unsigned __int64  uint64_t;
+  typedef signed __int64    int64_t;
+  // Definitions to avoid ICU redefinition issue
+  #define U_HAVE_INT8_T 1
+  #define U_HAVE_UINT8_T 1
+  #define U_HAVE_INT16_T 1
+  #define U_HAVE_UINT16_T 1
+  #define U_HAVE_INT32_T 1
+  #define U_HAVE_UINT32_T 1
+  #define U_HAVE_INT64_T 1
+  #define U_HAVE_UINT64_T 1
+#else
+  #include <stdint.h>
+#endif
+
+#include <cstddef>
+#include <vector>
+#include <set>
+
+namespace sfntly {
+
+typedef uint8_t   byte_t;
+typedef uint16_t  word_t;
+typedef uint32_t  dword_t;
+typedef uint64_t  qword_t;
+
+typedef std::vector<byte_t> ByteVector;
+typedef std::vector<int32_t> IntegerList;
+typedef std::set<int32_t> IntegerSet;
+
+// A macro to disallow the copy constructor and operator= functions.
+// This should be used in the private: declarations for a class.
+#define NO_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);               \
+  void operator=(const TypeName&)
+
+}  // namespace sfntly
+
+// Make google3 happy since it prohibits RTTI.
+template<typename To, typename From>
+inline To implicit_cast(From const &f) {
+  return f;
+}
+
+template<typename To, typename From>     // use like this: down_cast<T*>(foo);
+inline To down_cast(From* f) {                   // so we only accept pointers
+  // Ensures that To is a sub-type of From *.  This test is here only
+  // for compile-time type checking, and has no overhead in an
+  // optimized build at run-time, as it will be optimized away
+  // completely.
+#if defined (_MSC_VER)
+  #pragma warning(push)
+  #pragma warning(disable:4127)  // disable "conditional expression is constant"
+#endif
+  if (false) {
+    implicit_cast<From*, To>(0);
+  }
+#if defined (_MSC_VER)
+  #pragma warning(pop)
+#endif
+
+// The following code is the only place for RTTI.  It is done so to allow
+// additional type checking when SFNTLY_TYPE_VERIFICATION is defined.
+#if defined (SFNTLY_TYPE_VERIFICATION)
+  assert(f == NULL || dynamic_cast<To>(f) != NULL);
+#endif
+  return static_cast<To>(f);
+}
+
+#if !defined(WIN32)
+  #define UNREFERENCED_PARAMETER(p) do { (void)p; } while (0)
+#endif
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_TYPE_H_
diff --git a/cpp/src/sfntly/table/bitmap/big_glyph_metrics.cc b/cpp/src/sfntly/table/bitmap/big_glyph_metrics.cc
new file mode 100644
index 0000000..d853212
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/big_glyph_metrics.cc
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/big_glyph_metrics.h"
+
+namespace sfntly {
+/******************************************************************************
+ * BigGlyphMetrics class
+ ******************************************************************************/
+BigGlyphMetrics::BigGlyphMetrics(ReadableFontData* data)
+    : GlyphMetrics(data) {
+}
+
+BigGlyphMetrics::~BigGlyphMetrics() {
+}
+
+int32_t BigGlyphMetrics::Height() {
+  return data_->ReadByte(Offset::kHeight);
+}
+
+int32_t BigGlyphMetrics::Width() {
+  return data_->ReadByte(Offset::kWidth);
+}
+
+int32_t BigGlyphMetrics::HoriBearingX() {
+  return data_->ReadByte(Offset::kHoriBearingX);
+}
+
+int32_t BigGlyphMetrics::HoriBearingY() {
+  return data_->ReadByte(Offset::kHoriBearingY);
+}
+
+int32_t BigGlyphMetrics::HoriAdvance() {
+  return data_->ReadByte(Offset::kHoriAdvance);
+}
+
+int32_t BigGlyphMetrics::VertBearingX() {
+  return data_->ReadByte(Offset::kVertBearingX);
+}
+
+int32_t BigGlyphMetrics::VertBearingY() {
+  return data_->ReadByte(Offset::kVertBearingY);
+}
+
+int32_t BigGlyphMetrics::VertAdvance() {
+  return data_->ReadByte(Offset::kVertAdvance);
+}
+
+/******************************************************************************
+ * BigGlyphMetrics::Builder class
+ ******************************************************************************/
+BigGlyphMetrics::Builder::Builder(WritableFontData* data)
+    : GlyphMetrics::Builder(data) {
+}
+
+BigGlyphMetrics::Builder::Builder(ReadableFontData* data)
+    : GlyphMetrics::Builder(data) {
+}
+
+BigGlyphMetrics::Builder::~Builder() {
+}
+
+int32_t BigGlyphMetrics::Builder::Height() {
+  return InternalReadData()->ReadByte(Offset::kHeight);
+}
+
+void BigGlyphMetrics::Builder::SetHeight(byte_t height) {
+  InternalWriteData()->WriteByte(Offset::kHeight, height);
+}
+
+int32_t BigGlyphMetrics::Builder::Width() {
+  return InternalReadData()->ReadByte(Offset::kWidth);
+}
+
+void BigGlyphMetrics::Builder::SetWidth(byte_t width) {
+  InternalWriteData()->WriteByte(Offset::kWidth, width);
+}
+
+int32_t BigGlyphMetrics::Builder::HoriBearingX() {
+  return InternalReadData()->ReadByte(Offset::kHoriBearingX);
+}
+
+void BigGlyphMetrics::Builder::SetHoriBearingX(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kHoriBearingX, bearing);
+}
+
+int32_t BigGlyphMetrics::Builder::HoriBearingY() {
+  return InternalReadData()->ReadByte(Offset::kHoriBearingY);
+}
+
+void BigGlyphMetrics::Builder::SetHoriBearingY(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kHoriBearingY, bearing);
+}
+
+int32_t BigGlyphMetrics::Builder::HoriAdvance() {
+  return InternalReadData()->ReadByte(Offset::kHoriAdvance);
+}
+
+void BigGlyphMetrics::Builder::SetHoriAdvance(byte_t advance) {
+  InternalWriteData()->WriteByte(Offset::kHoriAdvance, advance);
+}
+
+int32_t BigGlyphMetrics::Builder::VertBearingX() {
+  return InternalReadData()->ReadByte(Offset::kVertBearingX);
+}
+
+void BigGlyphMetrics::Builder::SetVertBearingX(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kVertBearingX, bearing);
+}
+
+int32_t BigGlyphMetrics::Builder::VertBearingY() {
+  return InternalReadData()->ReadByte(Offset::kVertBearingY);
+}
+
+void BigGlyphMetrics::Builder::SetVertBearingY(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kVertBearingY, bearing);
+}
+
+int32_t BigGlyphMetrics::Builder::VertAdvance() {
+  return InternalReadData()->ReadByte(Offset::kVertAdvance);
+}
+
+void BigGlyphMetrics::Builder::SetVertAdvance(byte_t advance) {
+  InternalWriteData()->WriteByte(Offset::kVertAdvance, advance);
+}
+
+CALLER_ATTACH FontDataTable*
+    BigGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) {
+  BigGlyphMetricsPtr output = new BigGlyphMetrics(data);
+  return output.Detach();
+}
+
+void BigGlyphMetrics::Builder::SubDataSet() {
+  // NOP.
+}
+
+int32_t BigGlyphMetrics::Builder::SubDataSizeToSerialize() {
+  return 0;
+}
+
+bool BigGlyphMetrics::Builder::SubReadyToSerialize() {
+  return false;
+}
+
+int32_t BigGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) {
+  return Data()->CopyTo(new_data);
+}
+
+// static
+CALLER_ATTACH
+BigGlyphMetrics::Builder* BigGlyphMetrics::Builder::CreateBuilder() {
+  WritableFontDataPtr data;
+  data.Attach(WritableFontData::CreateWritableFontData(Offset::kMetricsLength));
+  BigGlyphMetricsBuilderPtr output = new BigGlyphMetrics::Builder(data);
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/big_glyph_metrics.h b/cpp/src/sfntly/table/bitmap/big_glyph_metrics.h
new file mode 100644
index 0000000..a91601c
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/big_glyph_metrics.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_
+
+#include "sfntly/table/bitmap/glyph_metrics.h"
+
+namespace sfntly {
+
+class BigGlyphMetrics : public GlyphMetrics,
+                        public RefCounted<BigGlyphMetrics> {
+ public:
+  struct Offset {
+    enum {
+      kMetricsLength = 8,
+
+      kHeight = 0,
+      kWidth = 1,
+      kHoriBearingX = 2,
+      kHoriBearingY = 3,
+      kHoriAdvance = 4,
+      kVertBearingX = 5,
+      kVertBearingY = 6,
+      kVertAdvance = 7,
+    };
+  };
+
+  class Builder : public GlyphMetrics::Builder,
+                  public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    explicit Builder(WritableFontData* data);
+    explicit Builder(ReadableFontData* data);
+
+    virtual ~Builder();
+
+    int32_t Height();
+    void SetHeight(byte_t height);
+    int32_t Width();
+    void SetWidth(byte_t width);
+    int32_t HoriBearingX();
+    void SetHoriBearingX(byte_t bearing);
+    int32_t HoriBearingY();
+    void SetHoriBearingY(byte_t bearing);
+    int32_t HoriAdvance();
+    void SetHoriAdvance(byte_t advance);
+    int32_t VertBearingX();
+    void SetVertBearingX(byte_t bearing);
+    int32_t VertBearingY();
+    void SetVertBearingY(byte_t bearing);
+    int32_t VertAdvance();
+    void SetVertAdvance(byte_t advance);
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    // Static instantiation function.
+    static CALLER_ATTACH Builder* CreateBuilder();
+  };
+
+  explicit BigGlyphMetrics(ReadableFontData* data);
+  virtual ~BigGlyphMetrics();
+
+  int32_t Height();
+  int32_t Width();
+  int32_t HoriBearingX();
+  int32_t HoriBearingY();
+  int32_t HoriAdvance();
+  int32_t VertBearingX();
+  int32_t VertBearingY();
+  int32_t VertAdvance();
+};
+typedef Ptr<BigGlyphMetrics> BigGlyphMetricsPtr;
+typedef Ptr<BigGlyphMetrics::Builder> BigGlyphMetricsBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BIG_GLYPH_METRICS_H_
diff --git a/cpp/src/sfntly/table/bitmap/bitmap_glyph.cc b/cpp/src/sfntly/table/bitmap/bitmap_glyph.cc
new file mode 100644
index 0000000..334a0c0
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/bitmap_glyph.cc
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0  = the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/bitmap_glyph.h"
+#include "sfntly/table/bitmap/simple_bitmap_glyph.h"
+#include "sfntly/table/bitmap/composite_bitmap_glyph.h"
+
+namespace sfntly {
+/******************************************************************************
+ * BitmapGlyph class
+ ******************************************************************************/
+BitmapGlyph::~BitmapGlyph() {
+}
+
+CALLER_ATTACH BitmapGlyph* BitmapGlyph::CreateGlyph(ReadableFontData* data,
+                                                    int32_t format) {
+  BitmapGlyphPtr glyph;
+  BitmapGlyphBuilderPtr builder;
+  builder.Attach(Builder::CreateGlyphBuilder(data, format));
+  if (builder) {
+    glyph.Attach(down_cast<BitmapGlyph*>(builder->Build()));
+  }
+  return glyph;
+}
+
+BitmapGlyph::BitmapGlyph(ReadableFontData* data, int32_t format)
+    : SubTable(data), format_(format) {
+}
+
+/******************************************************************************
+ * BitmapGlyph::Builder class
+ ******************************************************************************/
+BitmapGlyph::Builder::~Builder() {
+}
+
+CALLER_ATTACH BitmapGlyph::Builder*
+BitmapGlyph::Builder::CreateGlyphBuilder(ReadableFontData* data,
+                                         int32_t format) {
+  BitmapGlyphBuilderPtr builder;
+  switch (format) {
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+      builder = new SimpleBitmapGlyph::Builder(data, format);
+      break;
+    case 8:
+    case 9:
+      builder = new CompositeBitmapGlyph::Builder(data, format);
+      break;
+  }
+  return builder.Detach();
+}
+
+BitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format)
+    : SubTable::Builder(data), format_(format) {
+}
+
+BitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format)
+    : SubTable::Builder(data), format_(format) {
+}
+
+CALLER_ATTACH
+FontDataTable* BitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) {
+  UNREFERENCED_PARAMETER(data);
+  return NULL;
+}
+
+void BitmapGlyph::Builder::SubDataSet() {
+  // NOP
+}
+
+int32_t BitmapGlyph::Builder::SubDataSizeToSerialize() {
+  return InternalReadData()->Length();
+}
+
+bool BitmapGlyph::Builder::SubReadyToSerialize() {
+  return true;
+}
+
+int32_t BitmapGlyph::Builder::SubSerialize(WritableFontData* new_data) {
+  return InternalReadData()->CopyTo(new_data);
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/bitmap_glyph.h b/cpp/src/sfntly/table/bitmap/bitmap_glyph.h
new file mode 100644
index 0000000..2dd4c3a
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/bitmap_glyph.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0  = the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_
+
+#include <vector>
+#include <map>
+
+#include "sfntly/table/subtable.h"
+
+namespace sfntly {
+
+class BitmapGlyph : public SubTable {
+ public:
+  struct Offset {
+    enum {
+      // header
+      kVersion = 0,
+
+      kSmallGlyphMetricsLength = 5,
+      kBigGlyphMetricsLength = 8,
+      // format 1
+      kGlyphFormat1_imageData = kSmallGlyphMetricsLength,
+
+      // format 2
+      kGlyphFormat2_imageData = kSmallGlyphMetricsLength,
+
+      // format 3
+
+      // format 4
+
+      // format 5
+      kGlyphFormat5_imageData = 0,
+
+      // format 6
+      kGlyphFormat6_imageData = kBigGlyphMetricsLength,
+
+      // format 7
+      kGlyphFormat7_imageData = kBigGlyphMetricsLength,
+
+      // format 8
+      kGlyphFormat8_numComponents = kSmallGlyphMetricsLength + 1,
+      kGlyphFormat8_componentArray = kGlyphFormat8_numComponents +
+                                     DataSize::kUSHORT,
+
+      // format 9
+      kGlyphFormat9_numComponents = kBigGlyphMetricsLength,
+      kGlyphFormat9_componentArray = kGlyphFormat9_numComponents +
+                                     DataSize::kUSHORT,
+
+      // ebdtComponent
+      kEbdtComponentLength = DataSize::kUSHORT + 2 * DataSize::kCHAR,
+      kEbdtComponent_glyphCode = 0,
+      kEbdtComponent_xOffset = 2,
+      kEbdtComponent_yOffset = 3,
+    };
+  };
+
+  // TODO(stuartg): builder is not functional at all
+  // - need to add subclasses for each type of bitmap glyph
+  class Builder : public SubTable::Builder {
+   public:
+    virtual ~Builder();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    int32_t format() { return format_; }
+
+    static CALLER_ATTACH Builder* CreateGlyphBuilder(ReadableFontData* data,
+                                                     int32_t format);
+
+   protected:
+    Builder(WritableFontData* data, int32_t format);
+    Builder(ReadableFontData* data, int32_t format);
+
+   private:
+    int32_t format_;
+  };
+
+  virtual ~BitmapGlyph();
+
+  static CALLER_ATTACH BitmapGlyph* CreateGlyph(ReadableFontData* data,
+                                                int32_t format);
+  int32_t format() { return format_; }
+
+  // UNIMPLEMENTED: toString()
+
+ protected:
+  BitmapGlyph(ReadableFontData* data, int32_t format);
+
+ private:
+  int32_t format_;
+};
+typedef Ptr<BitmapGlyph> BitmapGlyphPtr;
+typedef Ptr<BitmapGlyph::Builder> BitmapGlyphBuilderPtr;
+typedef std::map<int32_t, BitmapGlyphBuilderPtr> BitmapGlyphBuilderMap;
+typedef std::vector<BitmapGlyphBuilderMap> BitmapGlyphBuilderList;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_GLYPH_H_
diff --git a/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.cc b/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.cc
new file mode 100644
index 0000000..ab9953b
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/bitmap_glyph_info.h"
+
+namespace sfntly {
+
+BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id,
+                                 int32_t block_offset,
+                                 int32_t start_offset,
+                                 int32_t length,
+                                 int32_t format)
+    : glyph_id_(glyph_id),
+      relative_(true),
+      block_offset_(block_offset),
+      start_offset_(start_offset),
+      length_(length),
+      format_(format) {
+}
+
+BitmapGlyphInfo::BitmapGlyphInfo(int32_t glyph_id,
+                                 int32_t start_offset,
+                                 int32_t length,
+                                 int32_t format)
+    : glyph_id_(glyph_id),
+      relative_(false),
+      block_offset_(0),
+      start_offset_(start_offset),
+      length_(length),
+      format_(format) {
+}
+
+bool BitmapGlyphInfo::operator==(const BitmapGlyphInfo& rhs) const {
+  return (format_ == rhs.format_ &&
+          glyph_id_ == rhs.glyph_id_ &&
+          length_ == rhs.length_ &&
+          offset() == rhs.offset());
+}
+
+bool BitmapGlyphInfo::operator==(BitmapGlyphInfo* rhs) {
+  if (rhs == NULL) {
+    return this == NULL;
+  }
+  return (format_ == rhs->format() &&
+          glyph_id_ == rhs->glyph_id() &&
+          length_ == rhs->length() &&
+          offset() == rhs->offset());
+}
+
+bool StartOffsetComparator::operator()(BitmapGlyphInfo* lhs,
+                                       BitmapGlyphInfo* rhs) {
+  return lhs->start_offset() > rhs->start_offset();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.h b/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.h
new file mode 100644
index 0000000..9921d0d
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/bitmap_glyph_info.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_
+
+#include <vector>
+#include <map>
+
+#include "sfntly/table/subtable.h"
+
+namespace sfntly {
+
+// An immutable class holding bitmap glyph information.
+class BitmapGlyphInfo : public RefCounted<BitmapGlyphInfo> {
+ public:
+  // Constructor for a relative located glyph. The glyph's position in the EBDT
+  // table is a combination of it's block offset and it's own start offset.
+  // @param glyphId the glyph id
+  // @param blockOffset the offset of the block to which the glyph belongs
+  // @param startOffset the offset of the glyph within the block
+  // @param length the byte length
+  // @param format the glyph image format
+  BitmapGlyphInfo(int32_t glyph_id,
+                  int32_t block_offset,
+                  int32_t start_offset,
+                  int32_t length,
+                  int32_t format);
+
+  // Constructor for an absolute located glyph. The glyph's position in the EBDT
+  // table is only given by it's own start offset.
+  // @param glyphId the glyph id
+  // @param startOffset the offset of the glyph within the block
+  // @param length the byte length
+  // @param format the glyph image format
+  BitmapGlyphInfo(int32_t glyph_id,
+                  int32_t start_offset,
+                  int32_t length,
+                  int32_t format);
+
+  int32_t glyph_id() const { return glyph_id_; }
+  bool relative() const { return relative_; }
+  int32_t block_offset() const { return block_offset_; }
+  int32_t offset() const { return block_offset() + start_offset(); }
+  int32_t start_offset() const { return start_offset_; }
+  int32_t length() const { return length_; }
+  int32_t format() const { return format_; }
+
+  // UNIMPLEMENTED: hashCode()
+  bool operator==(const BitmapGlyphInfo& rhs) const;
+  bool operator==(BitmapGlyphInfo* rhs);
+
+ private:
+  int32_t glyph_id_;
+  bool relative_;
+  int32_t block_offset_;
+  int32_t start_offset_;
+  int32_t length_;
+  int32_t format_;
+};
+typedef Ptr<BitmapGlyphInfo> BitmapGlyphInfoPtr;
+typedef std::map<int32_t, BitmapGlyphInfoPtr> BitmapGlyphInfoMap;
+typedef std::vector<BitmapGlyphInfoMap> BitmapLocaList;
+
+class StartOffsetComparator {
+ public:
+  bool operator()(BitmapGlyphInfo* lhs, BitmapGlyphInfo* rhs);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_INFO_H_
diff --git a/cpp/src/sfntly/table/bitmap/bitmap_size_table.cc b/cpp/src/sfntly/table/bitmap/bitmap_size_table.cc
new file mode 100644
index 0000000..6c7d731
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/bitmap_size_table.cc
@@ -0,0 +1,604 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0  = the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/bitmap_size_table.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sfntly/math/font_math.h"
+#include "sfntly/table/bitmap/eblc_table.h"
+#include "sfntly/table/bitmap/index_sub_table_format1.h"
+#include "sfntly/table/bitmap/index_sub_table_format2.h"
+#include "sfntly/table/bitmap/index_sub_table_format3.h"
+#include "sfntly/table/bitmap/index_sub_table_format4.h"
+#include "sfntly/table/bitmap/index_sub_table_format5.h"
+
+namespace sfntly {
+/******************************************************************************
+ * BitmapSizeTable class
+ ******************************************************************************/
+BitmapSizeTable::~BitmapSizeTable() {
+}
+
+int32_t BitmapSizeTable::IndexSubTableArrayOffset() {
+  return data_->ReadULongAsInt(
+      EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset);
+}
+
+int32_t BitmapSizeTable::IndexTableSize() {
+  return data_->ReadULongAsInt(
+      EblcTable::Offset::kBitmapSizeTable_indexTableSize);
+}
+
+int32_t BitmapSizeTable::NumberOfIndexSubTables() {
+  return NumberOfIndexSubTables(data_, 0);
+}
+
+int32_t BitmapSizeTable::ColorRef() {
+  return data_->ReadULongAsInt(EblcTable::Offset::kBitmapSizeTable_colorRef);
+}
+
+int32_t BitmapSizeTable::StartGlyphIndex() {
+  return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_startGlyphIndex);
+}
+
+int32_t BitmapSizeTable::EndGlyphIndex() {
+  return data_->ReadUShort(EblcTable::Offset::kBitmapSizeTable_endGlyphIndex);
+}
+
+int32_t BitmapSizeTable::PpemX() {
+  return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemX);
+}
+
+int32_t BitmapSizeTable::PpemY() {
+  return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_ppemY);
+}
+
+int32_t BitmapSizeTable::BitDepth() {
+  return data_->ReadByte(EblcTable::Offset::kBitmapSizeTable_bitDepth);
+}
+
+int32_t BitmapSizeTable::FlagsAsInt() {
+  return data_->ReadChar(EblcTable::Offset::kBitmapSizeTable_flags);
+}
+
+IndexSubTable* BitmapSizeTable::GetIndexSubTable(int32_t index) {
+  IndexSubTableList* subtable_list = GetIndexSubTableList();
+  if (index >= 0 && (size_t)index < subtable_list->size()) {
+    return (*subtable_list)[index];
+  }
+  return NULL;
+}
+
+int32_t BitmapSizeTable::GlyphOffset(int32_t glyph_id) {
+  IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->GlyphOffset(glyph_id);
+}
+
+int32_t BitmapSizeTable::GlyphLength(int32_t glyph_id) {
+  IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->GlyphLength(glyph_id);
+}
+
+CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::GlyphInfo(int32_t glyph_id) {
+  IndexSubTable* sub_table = SearchIndexSubTables(glyph_id);
+  if (sub_table == NULL) {
+    return NULL;
+  }
+  return sub_table->GlyphInfo(glyph_id);
+}
+
+int32_t BitmapSizeTable::GlyphFormat(int32_t glyph_id) {
+  IndexSubTable* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->image_format();
+}
+
+BitmapSizeTable::BitmapSizeTable(ReadableFontData* data,
+                                 ReadableFontData* master_data)
+    : SubTable(data, master_data) {
+}
+
+// static
+int32_t BitmapSizeTable::NumberOfIndexSubTables(ReadableFontData* data,
+                                                int32_t table_offset) {
+  return data->ReadULongAsInt(table_offset +
+      EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables);
+}
+
+IndexSubTable* BitmapSizeTable::SearchIndexSubTables(int32_t glyph_id) {
+  // would be faster to binary search but too many size tables don't have
+  // sorted subtables
+#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH)
+  return BinarySearchIndexSubTables(glyph_id);
+#else
+  return LinearSearchIndexSubTables(glyph_id);
+#endif
+}
+
+IndexSubTable* BitmapSizeTable::LinearSearchIndexSubTables(int32_t glyph_id) {
+  IndexSubTableList* subtable_list = GetIndexSubTableList();
+  for (IndexSubTableList::iterator b = subtable_list->begin(),
+                                   e = subtable_list->end(); b != e; b++) {
+    if ((*b)->first_glyph_index() <= glyph_id &&
+        (*b)->last_glyph_index() >= glyph_id) {
+      return *b;
+    }
+  }
+  return NULL;
+}
+
+IndexSubTable* BitmapSizeTable::BinarySearchIndexSubTables(int32_t glyph_id) {
+  IndexSubTableList* subtable_list = GetIndexSubTableList();
+  int32_t index = 0;
+  int32_t bottom = 0;
+  int32_t top = subtable_list->size();
+  while (top != bottom) {
+    index = (top + bottom) / 2;
+    IndexSubTable* subtable = (*subtable_list)[index];
+    if (glyph_id < subtable->first_glyph_index()) {
+      // Location beow current location
+      top = index;
+    } else {
+      if (glyph_id <= subtable->last_glyph_index()) {
+        return subtable;
+      } else {
+        bottom = index + 1;
+      }
+    }
+  }
+  return NULL;
+}
+
+CALLER_ATTACH
+IndexSubTable* BitmapSizeTable::CreateIndexSubTable(int32_t index) {
+  return IndexSubTable::CreateIndexSubTable(master_read_data(),
+                                            IndexSubTableArrayOffset(),
+                                            index);
+}
+
+IndexSubTableList* BitmapSizeTable::GetIndexSubTableList() {
+  AutoLock lock(index_subtables_lock_);
+  if (index_subtables_.empty()) {
+    for (int32_t i = 0; i < NumberOfIndexSubTables(); ++i) {
+      IndexSubTablePtr table;
+      table.Attach(CreateIndexSubTable(i));
+      index_subtables_.push_back(table);
+    }
+  }
+  return &index_subtables_;
+}
+
+/******************************************************************************
+ * BitmapSizeTable::Builder class
+ ******************************************************************************/
+BitmapSizeTable::Builder::~Builder() {
+}
+
+CALLER_ATTACH
+FontDataTable* BitmapSizeTable::Builder::SubBuildTable(ReadableFontData* data) {
+  BitmapSizeTablePtr output = new BitmapSizeTable(data, master_read_data());
+  return output.Detach();
+}
+
+void BitmapSizeTable::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t BitmapSizeTable::Builder::SubDataSizeToSerialize() {
+  IndexSubTableBuilderList* builders = IndexSubTableBuilders();
+  if (builders->empty()) {
+    return 0;
+  }
+  int32_t size = EblcTable::Offset::kBitmapSizeTableLength;
+  bool variable = false;
+  for (IndexSubTableBuilderList::iterator b = builders->begin(),
+                                          e = builders->end(); b != e; b++) {
+    size += EblcTable::Offset::kIndexSubTableEntryLength;
+    int32_t sub_table_size = (*b)->SubDataSizeToSerialize();
+    int32_t padding = FontMath::PaddingRequired(abs(sub_table_size),
+                                                DataSize::kULONG);
+#if defined (SFNTLY_DEBUG_BITMAP)
+    fprintf(stderr, "subtable size=%d\n", sub_table_size);
+#endif
+    variable = (sub_table_size > 0) ? variable : true;
+    size += abs(sub_table_size) + padding;
+  }
+#if defined (SFNTLY_DEBUG_BITMAP)
+  fprintf(stderr, "bitmap table size=%d\n", variable ? -size : size);
+#endif
+  return variable ? -size : size;
+}
+
+bool BitmapSizeTable::Builder::SubReadyToSerialize() {
+  if (IndexSubTableBuilders()->empty()) {
+    return false;
+  }
+  return true;
+}
+
+int32_t BitmapSizeTable::Builder::SubSerialize(WritableFontData* new_data) {
+  SetNumberOfIndexSubTables(IndexSubTableBuilders()->size());
+  int32_t size = InternalReadData()->CopyTo(new_data);
+  return size;
+}
+
+CALLER_ATTACH BitmapSizeTable::Builder*
+BitmapSizeTable::Builder::CreateBuilder(WritableFontData* data,
+                                        ReadableFontData* master_data) {
+  BitmapSizeTableBuilderPtr output =
+      new BitmapSizeTable::Builder(data, master_data);
+  return output.Detach();
+}
+
+CALLER_ATTACH BitmapSizeTable::Builder*
+BitmapSizeTable::Builder::CreateBuilder(ReadableFontData* data,
+                                        ReadableFontData* master_data) {
+  BitmapSizeTableBuilderPtr output =
+      new BitmapSizeTable::Builder(data, master_data);
+  return output.Detach();
+}
+
+int32_t BitmapSizeTable::Builder::IndexSubTableArrayOffset() {
+  return InternalReadData()->ReadULongAsInt(
+      EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset);
+}
+
+void BitmapSizeTable::Builder::SetIndexSubTableArrayOffset(int32_t offset) {
+  InternalWriteData()->WriteULong(
+      EblcTable::Offset::kBitmapSizeTable_indexSubTableArrayOffset, offset);
+}
+
+int32_t BitmapSizeTable::Builder::IndexTableSize() {
+  return InternalReadData()->ReadULongAsInt(
+      EblcTable::Offset::kBitmapSizeTable_indexTableSize);
+}
+
+void BitmapSizeTable::Builder::SetIndexTableSize(int32_t size) {
+  InternalWriteData()->WriteULong(
+      EblcTable::Offset::kBitmapSizeTable_indexTableSize, size);
+}
+
+int32_t BitmapSizeTable::Builder::NumberOfIndexSubTables() {
+  return GetIndexSubTableBuilders()->size();
+}
+
+int32_t BitmapSizeTable::Builder::ColorRef() {
+  return InternalReadData()->ReadULongAsInt(
+      EblcTable::Offset::kBitmapSizeTable_colorRef);
+}
+
+int32_t BitmapSizeTable::Builder::StartGlyphIndex() {
+  return InternalReadData()->ReadUShort(
+      EblcTable::Offset::kBitmapSizeTable_startGlyphIndex);
+}
+
+int32_t BitmapSizeTable::Builder::EndGlyphIndex() {
+  return InternalReadData()->ReadUShort(
+      EblcTable::Offset::kBitmapSizeTable_endGlyphIndex);
+}
+
+int32_t BitmapSizeTable::Builder::PpemX() {
+  return InternalReadData()->ReadByte(
+      EblcTable::Offset::kBitmapSizeTable_ppemX);
+}
+
+int32_t BitmapSizeTable::Builder::PpemY() {
+  return InternalReadData()->ReadByte(
+      EblcTable::Offset::kBitmapSizeTable_ppemY);
+}
+
+int32_t BitmapSizeTable::Builder::BitDepth() {
+  return InternalReadData()->ReadByte(
+      EblcTable::Offset::kBitmapSizeTable_bitDepth);
+}
+
+int32_t BitmapSizeTable::Builder::FlagsAsInt() {
+  return InternalReadData()->ReadChar(
+      EblcTable::Offset::kBitmapSizeTable_flags);
+}
+
+IndexSubTable::Builder* BitmapSizeTable::Builder::IndexSubTableBuilder(
+    int32_t index) {
+  IndexSubTableBuilderList* sub_table_list = GetIndexSubTableBuilders();
+  return sub_table_list->at(index);
+}
+
+CALLER_ATTACH BitmapGlyphInfo* BitmapSizeTable::Builder::GlyphInfo(
+    int32_t glyph_id) {
+  IndexSubTable::Builder* sub_table = SearchIndexSubTables(glyph_id);
+  if (sub_table == NULL) {
+    return NULL;
+  }
+  return sub_table->GlyphInfo(glyph_id);
+}
+
+int32_t BitmapSizeTable::Builder::GlyphOffset(int32_t glyph_id) {
+  IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->GlyphOffset(glyph_id);
+}
+
+int32_t BitmapSizeTable::Builder::GlyphLength(int32_t glyph_id) {
+  IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->GlyphLength(glyph_id);
+}
+
+int32_t BitmapSizeTable::Builder::GlyphFormat(int32_t glyph_id) {
+  IndexSubTable::Builder* subtable = SearchIndexSubTables(glyph_id);
+  if (subtable == NULL) {
+    return -1;
+  }
+  return subtable->image_format();
+}
+
+IndexSubTableBuilderList* BitmapSizeTable::Builder::IndexSubTableBuilders() {
+  return GetIndexSubTableBuilders();
+}
+
+CALLER_ATTACH BitmapSizeTable::Builder::BitmapGlyphInfoIterator*
+BitmapSizeTable::Builder::GetIterator() {
+  Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> output =
+      new BitmapSizeTable::Builder::BitmapGlyphInfoIterator(this);
+  return output.Detach();
+}
+
+void BitmapSizeTable::Builder::GenerateLocaMap(BitmapGlyphInfoMap* output) {
+  assert(output);
+  Ptr<BitmapSizeTable::Builder::BitmapGlyphInfoIterator> it;
+  it.Attach(GetIterator());
+  while (it->HasNext()) {
+    BitmapGlyphInfoPtr info;
+    info.Attach(it->Next());
+    (*output)[info->glyph_id()] = info;
+  }
+}
+
+void BitmapSizeTable::Builder::Revert() {
+  index_sub_tables_.clear();
+  set_model_changed(false);
+}
+
+BitmapSizeTable::Builder::Builder(WritableFontData* data,
+                                  ReadableFontData* master_data)
+    : SubTable::Builder(data, master_data) {
+}
+
+BitmapSizeTable::Builder::Builder(ReadableFontData* data,
+                                  ReadableFontData* master_data)
+    : SubTable::Builder(data, master_data) {
+}
+
+void BitmapSizeTable::Builder::SetNumberOfIndexSubTables(int32_t count) {
+  InternalWriteData()->WriteULong(
+      EblcTable::Offset::kBitmapSizeTable_numberOfIndexSubTables, count);
+}
+
+IndexSubTable::Builder* BitmapSizeTable::Builder::SearchIndexSubTables(
+    int32_t glyph_id) {
+  // would be faster to binary search but too many size tables don't have
+  // sorted subtables
+#if (SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH)
+  return BinarySearchIndexSubTables(glyph_id);
+#else
+  return LinearSearchIndexSubTables(glyph_id);
+#endif
+}
+
+IndexSubTable::Builder* BitmapSizeTable::Builder::LinearSearchIndexSubTables(
+    int32_t glyph_id) {
+  IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders();
+  for (IndexSubTableBuilderList::iterator b = subtable_list->begin(),
+                                          e = subtable_list->end();
+                                          b != e; b++) {
+    if ((*b)->first_glyph_index() <= glyph_id &&
+        (*b)->last_glyph_index() >= glyph_id) {
+      return *b;
+    }
+  }
+  return NULL;
+}
+
+IndexSubTable::Builder* BitmapSizeTable::Builder::BinarySearchIndexSubTables(
+    int32_t glyph_id) {
+  IndexSubTableBuilderList* subtable_list = GetIndexSubTableBuilders();
+  int32_t index = 0;
+  int32_t bottom = 0;
+  int32_t top = subtable_list->size();
+  while (top != bottom) {
+    index = (top + bottom) / 2;
+    IndexSubTable::Builder* subtable = subtable_list->at(index);
+    if (glyph_id < subtable->first_glyph_index()) {
+      // Location beow current location
+      top = index;
+    } else {
+      if (glyph_id <= subtable->last_glyph_index()) {
+        return subtable;
+      } else {
+        bottom = index + 1;
+      }
+    }
+  }
+  return NULL;
+}
+
+IndexSubTableBuilderList* BitmapSizeTable::Builder::GetIndexSubTableBuilders() {
+  if (index_sub_tables_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &index_sub_tables_;
+}
+
+void BitmapSizeTable::Builder::Initialize(ReadableFontData* data) {
+  index_sub_tables_.clear();
+  if (data) {
+    int32_t number_of_index_subtables =
+        BitmapSizeTable::NumberOfIndexSubTables(data, 0);
+    index_sub_tables_.resize(number_of_index_subtables);
+    for (int32_t i = 0; i < number_of_index_subtables; ++i) {
+      index_sub_tables_[i].Attach(CreateIndexSubTableBuilder(i));
+    }
+  }
+}
+
+CALLER_ATTACH IndexSubTable::Builder*
+BitmapSizeTable::Builder::CreateIndexSubTableBuilder(int32_t index) {
+  return IndexSubTable::Builder::CreateBuilder(master_read_data(),
+                                               IndexSubTableArrayOffset(),
+                                               index);
+}
+
+/******************************************************************************
+ * BitmapSizeTable::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+BitmapSizeTable::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    BitmapSizeTable::Builder* container)
+    : RefIterator<BitmapGlyphInfo, BitmapSizeTable::Builder>(container) {
+  sub_table_iter_ = container->IndexSubTableBuilders()->begin();
+  sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator());
+}
+
+bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (sub_table_glyph_info_iter_ && HasNext(sub_table_glyph_info_iter_)) {
+    return true;
+  }
+  while (++sub_table_iter_ != container()->IndexSubTableBuilders()->end()) {
+    sub_table_glyph_info_iter_.Attach((*sub_table_iter_)->GetIterator());
+    if (HasNext(sub_table_glyph_info_iter_)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+CALLER_ATTACH
+BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next() {
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  return Next(sub_table_glyph_info_iter_);
+}
+
+bool BitmapSizeTable::Builder::BitmapGlyphInfoIterator::HasNext(
+    BitmapGlyphInfoIter* iterator_base) {
+  if (iterator_base) {
+    switch (iterator_base->container_base()->index_format()) {
+      case 1: {
+        IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->HasNext();
+      }
+
+      case 2: {
+        IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->HasNext();
+      }
+
+      case 3: {
+        IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->HasNext();
+      }
+
+      case 4: {
+        IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->HasNext();
+      }
+
+      case 5: {
+        IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->HasNext();
+      }
+
+      default:
+        break;
+    }
+  }
+  return false;
+}
+
+CALLER_ATTACH
+BitmapGlyphInfo* BitmapSizeTable::Builder::BitmapGlyphInfoIterator::Next(
+    BitmapGlyphInfoIter* iterator_base) {
+  if (iterator_base) {
+    switch (iterator_base->container_base()->index_format()) {
+      case 1: {
+        IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->Next();
+      }
+
+      case 2: {
+        IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->Next();
+      }
+
+      case 3: {
+        IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->Next();
+      }
+
+      case 4: {
+        IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->Next();
+      }
+
+      case 5: {
+        IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator* it =
+            down_cast<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*>(
+                iterator_base);
+        return it->Next();
+      }
+
+      default:
+        break;
+    }
+  }
+  return NULL;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/bitmap_size_table.h b/cpp/src/sfntly/table/bitmap/bitmap_size_table.h
new file mode 100644
index 0000000..6733e20
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/bitmap_size_table.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0  = the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_
+
+#include "sfntly/port/lock.h"
+#include "sfntly/table/bitmap/bitmap_glyph_info.h"
+#include "sfntly/table/bitmap/index_sub_table.h"
+
+namespace sfntly {
+// Binary search would be faster but many fonts have index subtables that
+// aren't sorted.
+// Note: preprocessor define is used to avoid const expression warnings in C++
+//       code.
+#define SFNTLY_BITMAPSIZE_USE_BINARY_SEARCH 0
+
+class BitmapSizeTable : public SubTable,
+                        public RefCounted<BitmapSizeTable> {
+ public:
+  class Builder : public SubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator :
+        public RefIterator<BitmapGlyphInfo, Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      bool HasNext(BitmapGlyphInfoIter* iterator_base);
+      CALLER_ATTACH BitmapGlyphInfo* Next(BitmapGlyphInfoIter* iterator_base);
+
+      IndexSubTableBuilderList::iterator sub_table_iter_;
+      BitmapGlyphInfoIterPtr sub_table_glyph_info_iter_;
+    };
+
+    virtual ~Builder();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                ReadableFontData* master_data);
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                ReadableFontData* master_data);
+    // Gets the subtable array offset as set in the original table as read from
+    // the font file. This value cannot be explicitly set and will be generated
+    // during table building.
+    // @return the subtable array offset
+    int32_t IndexSubTableArrayOffset();
+
+    // Sets the subtable array offset. This is used only during the building
+    // process when the objects are being serialized.
+    // @param offset the offset to the index subtable array
+    void SetIndexSubTableArrayOffset(int32_t offset);
+
+    // Gets the subtable array size as set in the original table as read from
+    // the font file. This value cannot be explicitly set and will be generated
+    // during table building.
+    // @return the subtable array size
+    int32_t IndexTableSize();
+
+    // Sets the subtable size. This is used only during the building process
+    // when the objects are being serialized.
+    // @param size the offset to the index subtable array
+    void SetIndexTableSize(int32_t size);
+
+    int32_t NumberOfIndexSubTables();
+    int32_t ColorRef();
+    // TODO(stuartg): SBitLineMetrics hori();
+    // TODO(stuartg): SBitLineMetrics vert();
+    int32_t StartGlyphIndex();
+    int32_t EndGlyphIndex();
+    int32_t PpemX();
+    int32_t PpemY();
+    int32_t BitDepth();
+    int32_t FlagsAsInt();
+
+    IndexSubTable::Builder* IndexSubTableBuilder(int32_t index);
+    CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id);
+    int32_t GlyphOffset(int32_t glyph_id);
+    int32_t GlyphLength(int32_t glyph_id);
+    int32_t GlyphFormat(int32_t glyph_id);
+    IndexSubTableBuilderList* IndexSubTableBuilders();
+    // Note: renamed from iterator(), type is the derived type.
+    CALLER_ATTACH BitmapGlyphInfoIterator* GetIterator();
+    void GenerateLocaMap(BitmapGlyphInfoMap* output);
+
+   protected:
+    void Revert();
+
+   private:
+    Builder(WritableFontData* data, ReadableFontData* master_data);
+    Builder(ReadableFontData* data, ReadableFontData* master_data);
+
+    void SetNumberOfIndexSubTables(int32_t count);
+    IndexSubTable::Builder* SearchIndexSubTables(int32_t glyph_id);
+    IndexSubTable::Builder* LinearSearchIndexSubTables(int32_t glyph_id);
+    IndexSubTable::Builder* BinarySearchIndexSubTables(int32_t glyph_id);
+    IndexSubTableBuilderList* GetIndexSubTableBuilders();
+    void Initialize(ReadableFontData* data);
+    CALLER_ATTACH IndexSubTable::Builder* CreateIndexSubTableBuilder(
+        int32_t index);
+
+    IndexSubTableBuilderList index_sub_tables_;
+  };
+
+  virtual ~BitmapSizeTable();
+
+  int32_t IndexSubTableArrayOffset();
+  int32_t IndexTableSize();
+  int32_t NumberOfIndexSubTables();
+  int32_t ColorRef();
+  // TODO(stuartg): SBitLineMetrics hori();
+  // TODO(stuartg): SBitLineMetrics vert();
+  int32_t StartGlyphIndex();
+  int32_t EndGlyphIndex();
+  int32_t PpemX();
+  int32_t PpemY();
+  int32_t BitDepth();
+  int32_t FlagsAsInt();
+
+  // Note: renamed from indexSubTable()
+  IndexSubTable* GetIndexSubTable(int32_t index);
+  int32_t GlyphOffset(int32_t glyph_id);
+  int32_t GlyphLength(int32_t glyph_id);
+  CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id);
+  int32_t GlyphFormat(int32_t glyph_id);
+
+ protected:
+  BitmapSizeTable(ReadableFontData* data,
+                  ReadableFontData* master_data);
+
+ private:
+  static int32_t NumberOfIndexSubTables(ReadableFontData* data,
+                                        int32_t table_offset);
+  IndexSubTable* SearchIndexSubTables(int32_t glyph_id);
+  IndexSubTable* LinearSearchIndexSubTables(int32_t glyph_id);
+  IndexSubTable* BinarySearchIndexSubTables(int32_t glyph_id);
+  CALLER_ATTACH IndexSubTable* CreateIndexSubTable(int32_t index);
+  IndexSubTableList* GetIndexSubTableList();
+
+  Lock index_subtables_lock_;
+  IndexSubTableList index_subtables_;
+};
+typedef Ptr<BitmapSizeTable> BitmapSizeTablePtr;
+typedef std::vector<BitmapSizeTablePtr> BitmapSizeTableList;
+typedef Ptr<BitmapSizeTable::Builder> BitmapSizeTableBuilderPtr;
+typedef std::vector<BitmapSizeTableBuilderPtr> BitmapSizeTableBuilderList;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_BITMAP_SIZE_TABLE_H_
diff --git a/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.cc b/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.cc
new file mode 100644
index 0000000..ae7dc5a
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0  = the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/composite_bitmap_glyph.h"
+
+namespace sfntly {
+/******************************************************************************
+ * CompositeBitmapGlyph class
+ ******************************************************************************/
+CompositeBitmapGlyph::CompositeBitmapGlyph(ReadableFontData* data,
+                                           int32_t format)
+    : BitmapGlyph(data, format) {
+  Initialize(format);
+}
+
+CompositeBitmapGlyph::~CompositeBitmapGlyph() {
+}
+
+int32_t CompositeBitmapGlyph::NumComponents() {
+  return data_->ReadUShort(num_components_offset_);
+}
+
+CompositeBitmapGlyph::Component CompositeBitmapGlyph::GetComponent(
+    int32_t component_num) const {
+  int32_t component_offset = component_array_offset_ +
+                             component_num * Offset::kEbdtComponentLength;
+  return CompositeBitmapGlyph::Component(
+      data_->ReadUShort(component_offset + Offset::kEbdtComponent_glyphCode),
+      data_->ReadChar(component_offset + Offset::kEbdtComponent_xOffset),
+      data_->ReadChar(component_offset + Offset::kEbdtComponent_yOffset));
+}
+
+void CompositeBitmapGlyph::Initialize(int32_t format) {
+  if (format == 8) {
+    num_components_offset_ = Offset::kGlyphFormat8_numComponents;
+    component_array_offset_ = Offset::kGlyphFormat8_componentArray;
+  } else if (format == 9) {
+    num_components_offset_ = Offset::kGlyphFormat9_numComponents;
+    component_array_offset_ = Offset::kGlyphFormat9_componentArray;
+  } else {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IllegalStateException("Attempt to create a Composite Bitmap Glyph "
+                                "with a non-composite format.");
+#endif
+  }
+}
+
+/******************************************************************************
+ * CompositeBitmapGlyph::Component class
+ ******************************************************************************/
+CompositeBitmapGlyph::Component::Component(const Component& rhs)
+    : glyph_code_(rhs.glyph_code_),
+      x_offset_(rhs.x_offset_),
+      y_offset_(rhs.y_offset_) {
+}
+
+bool CompositeBitmapGlyph::Component::operator==(
+    const CompositeBitmapGlyph::Component& rhs) {
+  return glyph_code_ == rhs.glyph_code_;
+}
+
+CompositeBitmapGlyph::Component& CompositeBitmapGlyph::Component::operator=(
+    const CompositeBitmapGlyph::Component& rhs) {
+  glyph_code_ = rhs.glyph_code_;
+  x_offset_ = rhs.x_offset_;
+  y_offset_ = rhs.y_offset_;
+  return *this;
+}
+
+CompositeBitmapGlyph::Component::Component(int32_t glyph_code,
+                                           int32_t x_offset,
+                                           int32_t y_offset)
+    : glyph_code_(glyph_code), x_offset_(x_offset), y_offset_(y_offset) {
+}
+
+/******************************************************************************
+ * CompositeBitmapGlyph::Builder class
+ ******************************************************************************/
+CompositeBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format)
+    : BitmapGlyph::Builder(data, format) {
+}
+
+CompositeBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format)
+    : BitmapGlyph::Builder(data, format) {
+}
+
+CompositeBitmapGlyph::Builder::~Builder() {
+}
+
+CALLER_ATTACH FontDataTable*
+CompositeBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) {
+  Ptr<CompositeBitmapGlyph> glyph = new CompositeBitmapGlyph(data, format());
+  return glyph.Detach();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.h b/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.h
new file mode 100644
index 0000000..897db7e
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/composite_bitmap_glyph.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0  = the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_
+
+#include "sfntly/table/bitmap/bitmap_glyph.h"
+
+namespace sfntly {
+
+class CompositeBitmapGlyph : public BitmapGlyph,
+                             public RefCounted<CompositeBitmapGlyph> {
+ public:
+  class Component {
+   public:
+    Component(const Component& rhs);
+
+    int32_t glyph_code() { return glyph_code_; }
+    int32_t x_offset() { return x_offset_; }
+    int32_t y_offset() { return y_offset_; }
+
+    // UNIMPLEMENTED: int hashCode()
+    bool operator==(const Component& rhs);
+    Component& operator=(const Component& rhs);
+
+   protected:
+    Component(int32_t glyph_code, int32_t x_offset, int32_t y_offset);
+
+   private:
+    int32_t glyph_code_;
+    int32_t x_offset_;
+    int32_t y_offset_;
+
+    friend class CompositeBitmapGlyph;
+  };
+
+  class Builder : public BitmapGlyph::Builder,
+                  public RefCounted<Builder> {
+   public:
+    Builder(WritableFontData* data, int32_t format);
+    Builder(ReadableFontData* data, int32_t format);
+    virtual ~Builder();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+  };
+
+  CompositeBitmapGlyph(ReadableFontData* data, int32_t format);
+  virtual ~CompositeBitmapGlyph();
+  int32_t NumComponents();
+  // Note: returned immutable object over stack.
+  Component GetComponent(int32_t component_num) const;
+
+ private:
+  void Initialize(int32_t format);
+
+  int32_t num_components_offset_;
+  int32_t component_array_offset_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_COMPOSITE_BITMAP_GLYPH_H_
diff --git a/cpp/src/sfntly/table/bitmap/ebdt_table.cc b/cpp/src/sfntly/table/bitmap/ebdt_table.cc
new file mode 100644
index 0000000..eeb1fa0
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/ebdt_table.cc
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/ebdt_table.h"
+
+#include <stdlib.h>
+
+#include "sfntly/table/bitmap/composite_bitmap_glyph.h"
+#include "sfntly/table/bitmap/simple_bitmap_glyph.h"
+
+namespace sfntly {
+/******************************************************************************
+ * EbdtTable class
+ ******************************************************************************/
+EbdtTable::~EbdtTable() {
+}
+
+int32_t EbdtTable::Version() {
+  return data_->ReadFixed(Offset::kVersion);
+}
+
+CALLER_ATTACH
+BitmapGlyph* EbdtTable::Glyph(int32_t offset, int32_t length, int32_t format) {
+  ReadableFontDataPtr glyph_data;
+  glyph_data.Attach(down_cast<ReadableFontData*>(data_->Slice(offset, length)));
+  return BitmapGlyph::CreateGlyph(glyph_data, format);
+}
+
+EbdtTable::EbdtTable(Header* header, ReadableFontData* data)
+    : SubTableContainerTable(header, data) {
+}
+
+/******************************************************************************
+ * EbdtTable::Builder class
+ ******************************************************************************/
+EbdtTable::Builder::Builder(Header* header, WritableFontData* data)
+  : SubTableContainerTable::Builder(header, data) {
+}
+
+EbdtTable::Builder::Builder(Header* header, ReadableFontData* data)
+  : SubTableContainerTable::Builder(header, data) {
+}
+
+EbdtTable::Builder::~Builder() {
+}
+
+CALLER_ATTACH FontDataTable*
+    EbdtTable::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new EbdtTable(header(), data);
+  return table.Detach();
+}
+
+void EbdtTable::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t EbdtTable::Builder::SubDataSizeToSerialize() {
+  if (glyph_builders_.empty()) {
+    return 0;
+  }
+  bool fixed = true;
+  int32_t size = Offset::kHeaderLength;
+  for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(),
+                                        builder_end = glyph_builders_.end();
+                                        builder_map != builder_end;
+                                        builder_map++) {
+    for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(),
+                                         glyph_entry_end = builder_map->end();
+                                         glyph_entry != glyph_entry_end;
+                                         glyph_entry++) {
+      int32_t glyph_size = glyph_entry->second->SubDataSizeToSerialize();
+      size += abs(glyph_size);
+      fixed = (glyph_size <= 0) ? false : fixed;
+    }
+  }
+  return (fixed ? 1 : -1) * size;
+}
+
+bool EbdtTable::Builder::SubReadyToSerialize() {
+  if (glyph_builders_.empty()) {
+    return false;
+  }
+  return true;
+}
+
+int32_t EbdtTable::Builder::SubSerialize(WritableFontData* new_data) {
+  int32_t size = 0;
+  size += new_data->WriteFixed(Offset::kVersion, kVersion);
+  for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(),
+                                        builder_end = glyph_builders_.end();
+                                        builder_map != builder_end;
+                                        builder_map++) {
+    for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(),
+                                         glyph_entry_end = builder_map->end();
+                                         glyph_entry != glyph_entry_end;
+                                         glyph_entry++) {
+      WritableFontDataPtr slice;
+      slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size)));
+      size += glyph_entry->second->SubSerialize(slice);
+    }
+  }
+  return size;
+}
+
+void EbdtTable::Builder::SetLoca(BitmapLocaList* loca_list) {
+  assert(loca_list);
+  Revert();
+  glyph_loca_.resize(loca_list->size());
+  std::copy(loca_list->begin(), loca_list->end(), glyph_loca_.begin());
+}
+
+void EbdtTable::Builder::GenerateLocaList(BitmapLocaList* output) {
+  assert(output);
+  output->clear();
+
+  if (glyph_builders_.empty()) {
+    if (glyph_loca_.empty()) {
+      return;
+    }
+  }
+
+  int start_offset = Offset::kHeaderLength;
+  for (BitmapGlyphBuilderList::iterator builder_map = glyph_builders_.begin(),
+                                        builder_end = glyph_builders_.end();
+                                        builder_map != builder_end;
+                                        builder_map++) {
+    BitmapGlyphInfoMap new_loca_map;
+    int32_t glyph_offset = 0;
+    for (BitmapGlyphBuilderMap::iterator glyph_entry = builder_map->begin(),
+                                         glyph_end = builder_map->end();
+                                         glyph_entry != glyph_end;
+                                         glyph_entry++) {
+      BitmapGlyphBuilderPtr builder = glyph_entry->second;
+      int32_t size = builder->SubDataSizeToSerialize();
+      BitmapGlyphInfoPtr info = new BitmapGlyphInfo(glyph_entry->first,
+          start_offset + glyph_offset, size, builder->format());
+      new_loca_map[glyph_entry->first] = info;
+      glyph_offset += size;
+    }
+    start_offset += glyph_offset;
+    output->push_back(new_loca_map);
+  }
+}
+
+BitmapGlyphBuilderList* EbdtTable::Builder::GlyphBuilders() {
+  return GetGlyphBuilders();
+}
+
+void EbdtTable::Builder::SetGlyphBuilders(
+    BitmapGlyphBuilderList* glyph_builders) {
+  glyph_builders_.clear();
+  std::copy(glyph_builders->begin(), glyph_builders->end(),
+            glyph_builders_.begin());
+  set_model_changed();
+}
+
+void EbdtTable::Builder::Revert() {
+  glyph_loca_.clear();
+  glyph_builders_.clear();
+  set_model_changed(false);
+}
+
+CALLER_ATTACH
+EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header,
+                                                      WritableFontData* data) {
+  Ptr<EbdtTable::Builder> builder;
+  builder = new Builder(header, data);
+  return builder.Detach();
+}
+
+CALLER_ATTACH
+EbdtTable::Builder* EbdtTable::Builder::CreateBuilder(Header* header,
+                                                      ReadableFontData* data) {
+  Ptr<EbdtTable::Builder> builder;
+  builder = new Builder(header, data);
+  return builder.Detach();
+}
+
+BitmapGlyphBuilderList* EbdtTable::Builder::GetGlyphBuilders() {
+  if (glyph_builders_.empty()) {
+    if (glyph_loca_.empty()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IllegalStateException(
+          "Loca values not set - unable to parse glyph data.");
+#endif
+      return NULL;
+    }
+    Initialize(InternalReadData(), &glyph_loca_, &glyph_builders_);
+    set_model_changed();
+  }
+  return &glyph_builders_;
+}
+
+void EbdtTable::Builder::Initialize(ReadableFontData* data,
+                                    BitmapLocaList* loca_list,
+                                    BitmapGlyphBuilderList* output) {
+  assert(loca_list);
+  assert(output);
+
+  output->clear();
+  if (data) {
+    for (BitmapLocaList::iterator loca_map = loca_list->begin(),
+                                  loca_end = loca_list->end();
+                                  loca_map != loca_end; loca_map++) {
+      BitmapGlyphBuilderMap glyph_builder_map;
+      for (BitmapGlyphInfoMap::iterator entry = loca_map->begin(),
+                                        entry_end = loca_map->end();
+                                        entry != entry_end; entry++) {
+        BitmapGlyphInfoPtr info = entry->second;
+        ReadableFontDataPtr slice;
+        slice.Attach(down_cast<ReadableFontData*>(data->Slice(
+            info->offset(), info->length())));
+        BitmapGlyphBuilderPtr glyph_builder;
+        glyph_builder.Attach(BitmapGlyph::Builder::CreateGlyphBuilder(
+            slice, info->format()));
+        glyph_builder_map[entry->first] = glyph_builder;
+      }
+      output->push_back(glyph_builder_map);
+    }
+  }
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/ebdt_table.h b/cpp/src/sfntly/table/bitmap/ebdt_table.h
new file mode 100644
index 0000000..d138c14
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/ebdt_table.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_
+
+#include "sfntly/table/bitmap/bitmap_glyph.h"
+#include "sfntly/table/bitmap/bitmap_glyph_info.h"
+#include "sfntly/table/subtable_container_table.h"
+
+namespace sfntly {
+
+class EbdtTable : public SubTableContainerTable,
+                  public RefCounted<EbdtTable> {
+ public:
+  struct Offset {
+    enum {
+      kVersion = 0,
+      kHeaderLength = DataSize::kFixed,
+    };
+  };
+
+  class Builder : public SubTableContainerTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual void SubDataSet();
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+
+    void SetLoca(BitmapLocaList* loca_list);
+    void GenerateLocaList(BitmapLocaList* output);
+
+    // Gets the List of glyph builders for the glyph table builder. These may be
+    // manipulated in any way by the caller and the changes will be reflected in
+    // the final glyph table produced.
+    // If there is no current data for the glyph builder or the glyph builders
+    // have not been previously set then this will return an empty glyph builder
+    // List. If there is current data (i.e. data read from an existing font) and
+    // the loca list has not been set or is null, empty, or invalid, then an
+    // empty glyph builder List will be returned.
+    // @return the list of glyph builders
+    BitmapGlyphBuilderList* GlyphBuilders();
+
+    // Replace the internal glyph builders with the one provided. The provided
+    // list and all contained objects belong to this builder.
+    // This call is only required if the entire set of glyphs in the glyph
+    // table builder are being replaced. If the glyph builder list provided from
+    // the {@link EbdtTable.Builder#glyphBuilders()} is being used and modified
+    // then those changes will already be reflected in the glyph table builder.
+    // @param glyphBuilders the new glyph builders
+    void SetGlyphBuilders(BitmapGlyphBuilderList* glyph_builders);
+
+    void Revert();
+
+    // Create a new builder using the header information and data provided.
+    // @param header the header information
+    // @param data the data holding the table
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                ReadableFontData* data);
+
+   private:
+    BitmapGlyphBuilderList* GetGlyphBuilders();
+    static void Initialize(ReadableFontData* data,
+                           BitmapLocaList* loca_list,
+                           BitmapGlyphBuilderList* output);
+
+    static const int32_t kVersion = 0x00020000;  // TODO(stuartg): const/enum
+    BitmapLocaList glyph_loca_;
+    BitmapGlyphBuilderList glyph_builders_;
+  };
+
+  virtual ~EbdtTable();
+  int32_t Version();
+  CALLER_ATTACH BitmapGlyph* Glyph(int32_t offset,
+                                   int32_t length,
+                                   int32_t format);
+ protected:
+  EbdtTable(Header* header, ReadableFontData* data);
+};
+typedef Ptr<EbdtTable> EbdtTablePtr;
+typedef Ptr<EbdtTable::Builder> EbdtTableBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBDT_TABLE_H_
diff --git a/cpp/src/sfntly/table/bitmap/eblc_table.cc b/cpp/src/sfntly/table/bitmap/eblc_table.cc
new file mode 100644
index 0000000..0ad2764
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/eblc_table.cc
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "sfntly/math/font_math.h"
+
+namespace sfntly {
+/******************************************************************************
+ * EblcTable class
+ ******************************************************************************/
+int32_t EblcTable::Version() {
+  return data_->ReadFixed(Offset::kVersion);
+}
+
+int32_t EblcTable::NumSizes() {
+  return data_->ReadULongAsInt(Offset::kNumSizes);
+}
+
+BitmapSizeTable* EblcTable::GetBitmapSizeTable(int32_t index) {
+  if (index < 0 || index > NumSizes()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException(
+        "Size table index is outside the range of tables.");
+#endif
+    return NULL;
+  }
+  BitmapSizeTableList* bitmap_size_table_list = GetBitmapSizeTableList();
+  if (bitmap_size_table_list) {
+    return (*bitmap_size_table_list)[index];
+  }
+  return NULL;
+}
+
+EblcTable::EblcTable(Header* header, ReadableFontData* data)
+    : SubTableContainerTable(header, data) {
+}
+
+BitmapSizeTableList* EblcTable::GetBitmapSizeTableList() {
+  AutoLock lock(bitmap_size_table_lock_);
+  if (bitmap_size_table_.empty()) {
+    CreateBitmapSizeTable(data_, NumSizes(), &bitmap_size_table_);
+  }
+  return &bitmap_size_table_;
+}
+
+// static
+void EblcTable::CreateBitmapSizeTable(ReadableFontData* data,
+                                      int32_t num_sizes,
+                                      BitmapSizeTableList* output) {
+  assert(data);
+  assert(output);
+  for (int32_t i = 0; i < num_sizes; ++i) {
+    ReadableFontDataPtr new_data;
+    new_data.Attach(down_cast<ReadableFontData*>(
+        data->Slice(Offset::kBitmapSizeTableArrayStart +
+                    i * Offset::kBitmapSizeTableLength,
+                    Offset::kBitmapSizeTableLength)));
+    BitmapSizeTableBuilderPtr size_builder;
+    size_builder.Attach(
+        BitmapSizeTable::Builder::CreateBuilder(new_data, data));
+    BitmapSizeTablePtr size;
+    size.Attach(down_cast<BitmapSizeTable*>(size_builder->Build()));
+    output->push_back(size);
+  }
+}
+
+/******************************************************************************
+ * EblcTable::Builder class
+ ******************************************************************************/
+EblcTable::Builder::Builder(Header* header, WritableFontData* data)
+    : SubTableContainerTable::Builder(header, data) {
+}
+
+EblcTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : SubTableContainerTable::Builder(header, data) {
+}
+
+EblcTable::Builder::~Builder() {
+}
+
+int32_t EblcTable::Builder::SubSerialize(WritableFontData* new_data) {
+  // header
+  int32_t size = new_data->WriteFixed(0, kVersion);
+  size += new_data->WriteULong(size, size_table_builders_.size());
+
+  // calculate the offsets
+  // offset to the start of the size table array
+  int32_t size_table_start_offset = size;
+  // walking offset in the size table array
+  int32_t size_table_offset = size_table_start_offset;
+  // offset to the start of the whole index subtable block
+  int32_t sub_table_block_start_offset = size_table_offset +
+      size_table_builders_.size() * Offset::kBitmapSizeTableLength;
+  // walking offset in the index subtable
+  // points to the start of the current subtable block
+  int32_t current_sub_table_block_start_offset = sub_table_block_start_offset;
+
+#if defined (SFNTLY_DEBUG_BITMAP)
+  int32_t size_index = 0;
+#endif
+  for (BitmapSizeTableBuilderList::iterator
+           size_builder = size_table_builders_.begin(),
+           size_builder_end = size_table_builders_.end();
+       size_builder != size_builder_end; size_builder++) {
+    (*size_builder)->SetIndexSubTableArrayOffset(
+        current_sub_table_block_start_offset);
+    IndexSubTableBuilderList* index_sub_table_builder_list =
+        (*size_builder)->IndexSubTableBuilders();
+
+    // walking offset within the current subTable array
+    int32_t index_sub_table_array_offset = current_sub_table_block_start_offset;
+    // walking offset within the subTable entries
+    int32_t index_sub_table_offset = index_sub_table_array_offset +
+        index_sub_table_builder_list->size() * Offset::kIndexSubHeaderLength;
+
+#if defined (SFNTLY_DEBUG_BITMAP)
+    fprintf(stderr, "size %d: sizeTable=%x, current subTable Block=%x, ",
+            size_index, size_table_offset,
+            current_sub_table_block_start_offset);
+    fprintf(stderr, "index subTableStart=%x\n", index_sub_table_offset);
+    size_index++;
+    int32_t sub_table_index = 0;
+#endif
+    for (IndexSubTableBuilderList::iterator
+             index_sub_table_builder = index_sub_table_builder_list->begin(),
+             index_sub_table_builder_end = index_sub_table_builder_list->end();
+         index_sub_table_builder != index_sub_table_builder_end;
+         index_sub_table_builder++) {
+#if defined (SFNTLY_DEBUG_BITMAP)
+      fprintf(stderr, "\tsubTableIndex %d: format=%x, ", sub_table_index,
+              (*index_sub_table_builder)->index_format());
+      fprintf(stderr, "indexSubTableArrayOffset=%x, indexSubTableOffset=%x\n",
+              index_sub_table_array_offset, index_sub_table_offset);
+      sub_table_index++;
+#endif
+      // array entry
+      index_sub_table_array_offset += new_data->WriteUShort(
+          index_sub_table_array_offset,
+          (*index_sub_table_builder)->first_glyph_index());
+      index_sub_table_array_offset += new_data->WriteUShort(
+          index_sub_table_array_offset,
+          (*index_sub_table_builder)->last_glyph_index());
+      index_sub_table_array_offset += new_data->WriteULong(
+          index_sub_table_array_offset,
+          index_sub_table_offset - current_sub_table_block_start_offset);
+
+      // index sub table
+      WritableFontDataPtr slice_index_sub_table;
+      slice_index_sub_table.Attach(down_cast<WritableFontData*>(
+          new_data->Slice(index_sub_table_offset)));
+      int32_t current_sub_table_size =
+          (*index_sub_table_builder)->SubSerialize(slice_index_sub_table);
+      int32_t padding = FontMath::PaddingRequired(current_sub_table_size,
+                                                  DataSize::kULONG);
+#if defined (SFNTLY_DEBUG_BITMAP)
+      fprintf(stderr, "\t\tsubTableSize = %x, padding = %x\n",
+              current_sub_table_size, padding);
+#endif
+      index_sub_table_offset += current_sub_table_size;
+      index_sub_table_offset +=
+          new_data->WritePadding(index_sub_table_offset, padding);
+    }
+
+    // serialize size table
+    (*size_builder)->SetIndexTableSize(
+        index_sub_table_offset - current_sub_table_block_start_offset);
+    WritableFontDataPtr slice_size_table;
+    slice_size_table.Attach(down_cast<WritableFontData*>(
+        new_data->Slice(size_table_offset)));
+    size_table_offset += (*size_builder)->SubSerialize(slice_size_table);
+
+    current_sub_table_block_start_offset = index_sub_table_offset;
+  }
+  return size + current_sub_table_block_start_offset;
+}
+
+bool EblcTable::Builder::SubReadyToSerialize() {
+  if (size_table_builders_.empty()) {
+    return false;
+  }
+  for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(),
+                                            e = size_table_builders_.end();
+                                            b != e; b++) {
+    if (!(*b)->SubReadyToSerialize()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+int32_t EblcTable::Builder::SubDataSizeToSerialize() {
+  if (size_table_builders_.empty()) {
+    return 0;
+  }
+  int32_t size = Offset::kHeaderLength;
+  bool variable = false;
+#if defined (SFNTLY_DEBUG_BITMAP)
+  size_t size_index = 0;
+#endif
+  for (BitmapSizeTableBuilderList::iterator b = size_table_builders_.begin(),
+                                            e = size_table_builders_.end();
+                                            b != e; b++) {
+    int32_t size_builder_size = (*b)->SubDataSizeToSerialize();
+#if defined (SFNTLY_DEBUG_BITMAP)
+    fprintf(stderr, "sizeIndex = %d, sizeBuilderSize=0x%x (%d)\n",
+            size_index++, size_builder_size, size_builder_size);
+#endif
+    variable = size_builder_size > 0 ? variable : true;
+    size += abs(size_builder_size);
+  }
+#if defined (SFNTLY_DEBUG_BITMAP)
+  fprintf(stderr, "eblc size=%d\n", size);
+#endif
+  return variable ? -size : size;
+}
+
+void EblcTable::Builder::SubDataSet() {
+  Revert();
+}
+
+BitmapSizeTableBuilderList* EblcTable::Builder::BitmapSizeBuilders() {
+  return GetSizeList();
+}
+
+void EblcTable::Builder::Revert() {
+  size_table_builders_.clear();
+  set_model_changed(false);
+}
+
+void EblcTable::Builder::GenerateLocaList(BitmapLocaList* output) {
+  assert(output);
+  BitmapSizeTableBuilderList* size_builder_list = GetSizeList();
+  output->clear();
+#if defined (SFNTLY_DEBUG_BITMAP)
+  int32_t size_index = 0;
+#endif
+  for (BitmapSizeTableBuilderList::iterator b = size_builder_list->begin(),
+                                            e = size_builder_list->end();
+                                            b != e; b++) {
+#if defined (SFNTLY_DEBUG_BITMAP)
+    fprintf(stderr, "size table = %d\n", size_index++);
+#endif
+    BitmapGlyphInfoMap loca_map;
+    (*b)->GenerateLocaMap(&loca_map);
+    output->push_back(loca_map);
+  }
+}
+
+CALLER_ATTACH
+FontDataTable* EblcTable::Builder::SubBuildTable(ReadableFontData* data) {
+  Ptr<EblcTable> new_table = new EblcTable(header(), data);
+  return new_table.Detach();
+}
+
+// static
+CALLER_ATTACH EblcTable::Builder*
+    EblcTable::Builder::CreateBuilder(Header* header, WritableFontData* data) {
+  Ptr<EblcTable::Builder> new_builder = new EblcTable::Builder(header, data);
+  return new_builder.Detach();
+}
+
+// static
+CALLER_ATTACH EblcTable::Builder*
+    EblcTable::Builder::CreateBuilder(Header* header, ReadableFontData* data) {
+  Ptr<EblcTable::Builder> new_builder = new EblcTable::Builder(header, data);
+  return new_builder.Detach();
+}
+
+BitmapSizeTableBuilderList* EblcTable::Builder::GetSizeList() {
+  if (size_table_builders_.empty()) {
+    Initialize(InternalReadData(), &size_table_builders_);
+    set_model_changed();
+  }
+  return &size_table_builders_;
+}
+
+void EblcTable::Builder::Initialize(ReadableFontData* data,
+                                    BitmapSizeTableBuilderList* output) {
+  assert(output);
+  if (data) {
+    int32_t num_sizes = data->ReadULongAsInt(Offset::kNumSizes);
+    for (int32_t i = 0; i < num_sizes; ++i) {
+      ReadableFontDataPtr new_data;
+      new_data.Attach(down_cast<ReadableFontData*>(
+          data->Slice(Offset::kBitmapSizeTableArrayStart +
+                      i * Offset::kBitmapSizeTableLength,
+                      Offset::kBitmapSizeTableLength)));
+      BitmapSizeTableBuilderPtr size_builder;
+      size_builder.Attach(BitmapSizeTable::Builder::CreateBuilder(
+          new_data, data));
+      output->push_back(size_builder);
+    }
+  }
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/eblc_table.h b/cpp/src/sfntly/table/bitmap/eblc_table.h
new file mode 100644
index 0000000..b04338a
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/eblc_table.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_
+
+#include "sfntly/port/lock.h"
+#include "sfntly/table/bitmap/big_glyph_metrics.h"
+#include "sfntly/table/bitmap/bitmap_glyph.h"
+#include "sfntly/table/bitmap/bitmap_size_table.h"
+#include "sfntly/table/subtable_container_table.h"
+
+namespace sfntly {
+
+class EblcTable : public SubTableContainerTable,
+                  public RefCounted<EblcTable> {
+ public:
+  struct Offset {
+    enum {
+      // header
+      kVersion = 0,
+      kNumSizes = 4,
+      kHeaderLength = kNumSizes + DataSize::kULONG,
+
+      // bitmapSizeTable
+      kBitmapSizeTableArrayStart = kHeaderLength,
+      kBitmapSizeTableLength = 48,
+      kBitmapSizeTable_indexSubTableArrayOffset = 0,
+      kBitmapSizeTable_indexTableSize = 4,
+      kBitmapSizeTable_numberOfIndexSubTables = 8,
+      kBitmapSizeTable_colorRef = 12,
+      kBitmapSizeTable_hori = 16,
+      kBitmapSizeTable_vert = 28,
+      kBitmapSizeTable_startGlyphIndex = 40,
+      kBitmapSizeTable_endGlyphIndex = 42,
+      kBitmapSizeTable_ppemX = 44,
+      kBitmapSizeTable_ppemY = 45,
+      kBitmapSizeTable_bitDepth = 46,
+      kBitmapSizeTable_flags = 47,
+
+      // sbitLineMetrics
+      kSbitLineMetricsLength = 12,
+      kSbitLineMetrics_ascender = 0,
+      kSbitLineMetrics_descender = 1,
+      kSbitLineMetrics_widthMax = 2,
+      kSbitLineMetrics_caretSlopeNumerator = 3,
+      kSbitLineMetrics_caretSlopeDenominator = 4,
+      kSbitLineMetrics_caretOffset = 5,
+      kSbitLineMetrics_minOriginSB = 6,
+      kSbitLineMetrics_minAdvanceSB = 7,
+      kSbitLineMetrics_maxBeforeBL = 8,
+      kSbitLineMetrics_minAfterBL = 9,
+      kSbitLineMetrics_pad1 = 10,
+      kSbitLineMetrics_pad2 = 11,
+
+      // indexSubTable
+      kIndexSubTableEntryLength = 8,
+      kIndexSubTableEntry_firstGlyphIndex = 0,
+      kIndexSubTableEntry_lastGlyphIndex = 2,
+      kIndexSubTableEntry_additionalOffsetToIndexSubTable = 4,
+
+      // indexSubHeader
+      kIndexSubHeaderLength = 8,
+      kIndexSubHeader_indexFormat = 0,
+      kIndexSubHeader_imageFormat = 2,
+      kIndexSubHeader_imageDataOffset = 4,
+
+      // indexSubTable - all offset relative to the subtable start
+
+      // indexSubTable1
+      kIndexSubTable1_offsetArray = kIndexSubHeaderLength,
+      kIndexSubTable1_builderDataSize = kIndexSubHeaderLength,
+
+      // kIndexSubTable2
+      kIndexSubTable2Length = kIndexSubHeaderLength +
+                              DataSize::kULONG +
+                              BitmapGlyph::Offset::kBigGlyphMetricsLength,
+      kIndexSubTable2_imageSize = kIndexSubHeaderLength,
+      kIndexSubTable2_bigGlyphMetrics = kIndexSubTable2_imageSize +
+                                        DataSize::kULONG,
+      kIndexSubTable2_builderDataSize = kIndexSubTable2_bigGlyphMetrics +
+                                        BigGlyphMetrics::Offset::kMetricsLength,
+
+      // kIndexSubTable3
+      kIndexSubTable3_offsetArray = kIndexSubHeaderLength,
+      kIndexSubTable3_builderDataSize = kIndexSubTable3_offsetArray,
+
+      // kIndexSubTable4
+      kIndexSubTable4_numGlyphs = kIndexSubHeaderLength,
+      kIndexSubTable4_glyphArray = kIndexSubTable4_numGlyphs +
+                                   DataSize::kULONG,
+      kIndexSubTable4_codeOffsetPairLength = 2 * DataSize::kUSHORT,
+      kIndexSubTable4_codeOffsetPair_glyphCode = 0,
+      kIndexSubTable4_codeOffsetPair_offset = DataSize::kUSHORT,
+      kIndexSubTable4_builderDataSize = kIndexSubTable4_glyphArray,
+
+      // kIndexSubTable5
+      kIndexSubTable5_imageSize = kIndexSubHeaderLength,
+      kIndexSubTable5_bigGlyphMetrics = kIndexSubTable5_imageSize +
+                                        DataSize::kULONG,
+      kIndexSubTable5_numGlyphs = kIndexSubTable5_bigGlyphMetrics +
+                                  BitmapGlyph::Offset::kBigGlyphMetricsLength,
+      kIndexSubTable5_glyphArray = kIndexSubTable5_numGlyphs +
+                                   DataSize::kULONG,
+      kIndexSubTable5_builderDataSize = kIndexSubTable5_glyphArray,
+
+      // codeOffsetPair
+      kCodeOffsetPairLength = 2 * DataSize::kUSHORT,
+      kCodeOffsetPair_glyphCode = 0,
+      kCodeOffsetPair_offset = DataSize::kUSHORT,
+    };
+  };
+
+  class Builder : public SubTableContainerTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual void SubDataSet();
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+
+    BitmapSizeTableBuilderList* BitmapSizeBuilders();
+    void Revert();
+
+    // Generates the loca list for the EBDT table. The list is intended to be
+    // used by the EBDT to allow it to parse the glyph data and generate glyph
+    // objects. After returning from this method the list belongs to the caller.
+    // The list entries are in the same order as the size table builders are at
+    // the time of this call.
+    // @return the list of loca maps with one for each size table builder
+    void GenerateLocaList(BitmapLocaList* output);
+
+    // Create a new builder using the header information and data provided.
+    // @param header the header information
+    // @param data the data holding the table
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                ReadableFontData* data);
+
+   private:
+    BitmapSizeTableBuilderList* GetSizeList();
+    void Initialize(ReadableFontData* data, BitmapSizeTableBuilderList* output);
+
+    static const int32_t kVersion = 0x00020000;
+    BitmapSizeTableBuilderList size_table_builders_;
+  };
+
+  int32_t Version();
+  int32_t NumSizes();
+  // UNIMPLEMENTED: toString()
+
+  BitmapSizeTable* GetBitmapSizeTable(int32_t index);
+
+  static const int32_t NOTDEF = -1;
+
+ protected:
+  EblcTable(Header* header, ReadableFontData* data);
+
+ private:
+  BitmapSizeTableList* GetBitmapSizeTableList();
+
+  static void CreateBitmapSizeTable(ReadableFontData* data,
+                                    int32_t num_sizes,
+                                    BitmapSizeTableList* output);
+
+  Lock bitmap_size_table_lock_;
+  BitmapSizeTableList bitmap_size_table_;
+};
+typedef Ptr<EblcTable> EblcTablePtr;
+typedef Ptr<EblcTable::Builder> EblcTableBuilderPtr;
+}
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBLC_TABLE_H_
diff --git a/cpp/src/sfntly/table/bitmap/ebsc_table.cc b/cpp/src/sfntly/table/bitmap/ebsc_table.cc
new file mode 100644
index 0000000..458c2d4
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/ebsc_table.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/ebsc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * EbscTable class
+ ******************************************************************************/
+EbscTable::~EbscTable() {
+}
+
+int32_t EbscTable::Version() {
+  return data_->ReadFixed(Offset::kVersion);
+}
+
+int32_t EbscTable::NumSizes() {
+  return data_->ReadULongAsInt(Offset::kNumSizes);
+}
+
+EbscTable::EbscTable(Header* header, ReadableFontData* data)
+    : Table(header, data) {
+}
+
+/******************************************************************************
+ * EbscTable::BitmapScaleTable class
+ ******************************************************************************/
+EbscTable::BitmapScaleTable::~BitmapScaleTable() {
+}
+
+EbscTable::BitmapScaleTable::BitmapScaleTable(ReadableFontData* data)
+    : SubTable(data) {
+}
+
+int32_t EbscTable::BitmapScaleTable::PpemX() {
+  return data_->ReadByte(Offset::kBitmapScaleTable_ppemX);
+}
+
+int32_t EbscTable::BitmapScaleTable::PpemY() {
+  return data_->ReadByte(Offset::kBitmapScaleTable_ppemY);
+}
+
+int32_t EbscTable::BitmapScaleTable::SubstitutePpemX() {
+  return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemX);
+}
+
+int32_t EbscTable::BitmapScaleTable::SubstitutePpemY() {
+  return data_->ReadByte(Offset::kBitmapScaleTable_substitutePpemY);
+}
+
+/******************************************************************************
+ * EbscTable::Builder class
+ ******************************************************************************/
+EbscTable::Builder::~Builder() {
+}
+
+CALLER_ATTACH EbscTable::Builder* EbscTable::Builder::CreateBuilder(
+    Header* header, WritableFontData* data) {
+  EbscTableBuilderPtr builder = new EbscTable::Builder(header, data);
+  return builder.Detach();
+}
+
+EbscTable::Builder::Builder(Header* header, WritableFontData* data)
+    : Table::Builder(header, data) {
+}
+
+EbscTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : Table::Builder(header, data) {
+}
+
+CALLER_ATTACH
+FontDataTable* EbscTable::Builder::SubBuildTable(ReadableFontData* data) {
+  EbscTablePtr output = new EbscTable(header(), data);
+  return output.Detach();
+}
+
+void EbscTable::Builder::SubDataSet() {
+  // NOP
+}
+
+int32_t EbscTable::Builder::SubDataSizeToSerialize() {
+  return 0;
+}
+
+bool EbscTable::Builder::SubReadyToSerialize() {
+  return false;
+}
+
+int32_t EbscTable::Builder::SubSerialize(WritableFontData* new_data) {
+  UNREFERENCED_PARAMETER(new_data);
+  return 0;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/ebsc_table.h b/cpp/src/sfntly/table/bitmap/ebsc_table.h
new file mode 100644
index 0000000..b79df38
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/ebsc_table.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+
+class EbscTable : public Table,
+                  public RefCounted<EbscTable> {
+ public:
+  struct Offset {
+    enum {
+      // header
+      kVersion = 0,
+      kNumSizes = DataSize::kFixed,
+      kHeaderLength = kNumSizes + DataSize::kULONG,
+      kBitmapScaleTableStart = kHeaderLength,
+
+      // bitmapScaleTable
+      kBitmapScaleTable_hori = 0,
+      kBitmapScaleTable_vert = EblcTable::Offset::kSbitLineMetricsLength,
+      kBitmapScaleTable_ppemX = kBitmapScaleTable_vert +
+                                EblcTable::Offset::kSbitLineMetricsLength,
+      kBitmapScaleTable_ppemY = kBitmapScaleTable_ppemX + DataSize::kBYTE,
+      kBitmapScaleTable_substitutePpemX = kBitmapScaleTable_ppemY +
+                                          DataSize::kBYTE,
+      kBitmapScaleTable_substitutePpemY = kBitmapScaleTable_substitutePpemX +
+                                          DataSize::kBYTE,
+      kBitmapScaleTableLength = kBitmapScaleTable_substitutePpemY +
+                                DataSize::kBYTE,
+    };
+  };
+
+  class BitmapScaleTable : public SubTable,
+                           public RefCounted<BitmapScaleTable> {
+   public:
+    virtual ~BitmapScaleTable();
+    int32_t PpemX();
+    int32_t PpemY();
+    int32_t SubstitutePpemX();
+    int32_t SubstitutePpemY();
+
+   protected:
+    // Note: caller to do data->Slice(offset, Offset::kBitmapScaleTableLength)
+    explicit BitmapScaleTable(ReadableFontData* data);
+  };
+
+  // TODO(stuartg): currently the builder just builds from initial data
+  // - need to make fully working but few if any examples to test with
+  class Builder : public Table::Builder,
+                  public RefCounted<Builder> {
+   public:
+    virtual ~Builder();
+
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+
+   protected:
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+  };
+
+  virtual ~EbscTable();
+
+  int32_t Version();
+  int32_t NumSizes();
+  // Note: renamed from bitmapScaleTable
+  CALLER_ATTACH BitmapScaleTable* GetBitmapScaleTable(int32_t index);
+
+ private:
+  EbscTable(Header* header, ReadableFontData* data);
+  friend class Builder;
+};
+typedef Ptr<EbscTable> EbscTablePtr;
+typedef Ptr<EbscTable::Builder> EbscTableBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_EBSC_TABLE_H_
diff --git a/cpp/src/sfntly/table/bitmap/glyph_metrics.cc b/cpp/src/sfntly/table/bitmap/glyph_metrics.cc
new file mode 100644
index 0000000..e91eb99
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/glyph_metrics.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/glyph_metrics.h"
+
+namespace sfntly {
+
+GlyphMetrics::~GlyphMetrics() {
+}
+
+GlyphMetrics::GlyphMetrics(ReadableFontData* data)
+    : SubTable(data) {
+}
+
+GlyphMetrics::Builder::~Builder() {
+}
+
+GlyphMetrics::Builder::Builder(WritableFontData* data)
+    : SubTable::Builder(data) {
+}
+
+GlyphMetrics::Builder::Builder(ReadableFontData* data)
+    : SubTable::Builder(data) {
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/glyph_metrics.h b/cpp/src/sfntly/table/bitmap/glyph_metrics.h
new file mode 100644
index 0000000..5f16aaa
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/glyph_metrics.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_
+
+#include "sfntly/table/subtable.h"
+
+namespace sfntly {
+
+class GlyphMetrics : public SubTable {
+ public:
+  virtual ~GlyphMetrics();
+
+ protected:
+  class Builder : public SubTable::Builder {
+   public:
+    virtual ~Builder();
+
+   protected:
+    explicit Builder(WritableFontData* data);
+    explicit Builder(ReadableFontData* data);
+  };
+
+  explicit GlyphMetrics(ReadableFontData* data);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_GLYPH_METRICS_H_
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table.cc b/cpp/src/sfntly/table/bitmap/index_sub_table.cc
new file mode 100644
index 0000000..5e29784
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table.cc
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/index_sub_table.h"
+
+#include "sfntly/table/bitmap/eblc_table.h"
+#include "sfntly/table/bitmap/index_sub_table_format1.h"
+#include "sfntly/table/bitmap/index_sub_table_format2.h"
+#include "sfntly/table/bitmap/index_sub_table_format3.h"
+#include "sfntly/table/bitmap/index_sub_table_format4.h"
+#include "sfntly/table/bitmap/index_sub_table_format5.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTable class
+ ******************************************************************************/
+CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::GlyphInfo(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return NULL;
+  }
+  if (GlyphStartOffset(glyph_id) == -1) {
+    return NULL;
+  }
+  BitmapGlyphInfoPtr output = new BitmapGlyphInfo(glyph_id,
+                                                  image_data_offset(),
+                                                  GlyphStartOffset(glyph_id),
+                                                  GlyphLength(glyph_id),
+                                                  image_format());
+  return output.Detach();
+}
+
+int32_t IndexSubTable::GlyphOffset(int32_t glyph_id) {
+  int32_t glyph_start_offset = GlyphStartOffset(glyph_id);
+  if (glyph_start_offset == -1) {
+    return -1;
+  }
+  return image_data_offset() + glyph_start_offset;
+}
+
+// static
+CALLER_ATTACH IndexSubTable*
+    IndexSubTable::CreateIndexSubTable(ReadableFontData* data,
+                                       int32_t offset_to_index_sub_table_array,
+                                       int32_t array_index) {
+  IndexSubTableBuilderPtr builder;
+  builder.Attach(IndexSubTable::Builder::CreateBuilder(
+      data, offset_to_index_sub_table_array, array_index));
+  return down_cast<IndexSubTable*>(builder->Build());
+}
+
+IndexSubTable::IndexSubTable(ReadableFontData* data,
+                             int32_t first_glyph_index,
+                             int32_t last_glyph_index)
+    : SubTable(data),
+      first_glyph_index_(first_glyph_index),
+      last_glyph_index_(last_glyph_index) {
+  index_format_ =
+      data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat);
+  image_format_ =
+      data_->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat);
+  image_data_offset_ =
+      data_->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset);
+}
+
+int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id) {
+  return CheckGlyphRange(glyph_id, first_glyph_index(), last_glyph_index());
+}
+
+// static
+int32_t IndexSubTable::CheckGlyphRange(int32_t glyph_id,
+                                       int32_t first_glyph_id,
+                                       int32_t last_glyph_id) {
+  if (glyph_id < first_glyph_id || glyph_id > last_glyph_id) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException("Glyph ID is outside of the allowed range.");
+#endif
+    return -1;
+  }
+  return glyph_id - first_glyph_id;
+}
+
+/******************************************************************************
+ * IndexSubTable::Builder class
+ ******************************************************************************/
+IndexSubTable::Builder::~Builder() {
+}
+
+void IndexSubTable::Builder::Revert() {
+  set_model_changed(false);
+  Initialize(InternalReadData());
+}
+
+CALLER_ATTACH BitmapGlyphInfo* IndexSubTable::Builder::GlyphInfo(
+    int32_t glyph_id) {
+  BitmapGlyphInfoPtr glyph_info =
+      new BitmapGlyphInfo(glyph_id,
+                          image_data_offset(),
+                          GlyphStartOffset(glyph_id),
+                          GlyphLength(glyph_id),
+                          image_format());
+  return glyph_info.Detach();
+}
+
+int32_t IndexSubTable::Builder::GlyphOffset(int32_t glyph_id) {
+  return image_data_offset() + GlyphStartOffset(glyph_id);
+}
+
+// static
+CALLER_ATTACH IndexSubTable::Builder*
+IndexSubTable::Builder::CreateBuilder(int32_t index_format) {
+  switch (index_format) {
+    case Format::FORMAT_1:
+      return IndexSubTableFormat1::Builder::CreateBuilder();
+    case Format::FORMAT_2:
+      return IndexSubTableFormat2::Builder::CreateBuilder();
+    case Format::FORMAT_3:
+      return IndexSubTableFormat3::Builder::CreateBuilder();
+    case Format::FORMAT_4:
+      return IndexSubTableFormat4::Builder::CreateBuilder();
+    case Format::FORMAT_5:
+      return IndexSubTableFormat5::Builder::CreateBuilder();
+    default:
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IllegalArgumentException("Invalid index subtable format");
+#endif
+      return NULL;
+  }
+}
+
+// static
+CALLER_ATTACH IndexSubTable::Builder*
+IndexSubTable::Builder::CreateBuilder(ReadableFontData* data,
+    int32_t offset_to_index_sub_table_array, int32_t array_index) {
+  int32_t index_sub_table_entry_offset =
+      offset_to_index_sub_table_array +
+      array_index * EblcTable::Offset::kIndexSubTableEntryLength;
+  int32_t first_glyph_index =
+      data->ReadUShort(index_sub_table_entry_offset +
+                       EblcTable::Offset::kIndexSubTableEntry_firstGlyphIndex);
+  int32_t last_glyph_index =
+      data->ReadUShort(index_sub_table_entry_offset +
+                       EblcTable::Offset::kIndexSubTableEntry_lastGlyphIndex);
+  int32_t additional_offset_to_index_subtable = data->ReadULongAsInt(
+      index_sub_table_entry_offset +
+      EblcTable::Offset::kIndexSubTableEntry_additionalOffsetToIndexSubTable);
+  int32_t index_sub_table_offset = offset_to_index_sub_table_array +
+                                   additional_offset_to_index_subtable;
+  int32_t index_format = data->ReadUShort(index_sub_table_offset);
+  switch (index_format) {
+    case 1:
+      return IndexSubTableFormat1::Builder::CreateBuilder(
+          data, index_sub_table_offset, first_glyph_index, last_glyph_index);
+    case 2:
+      return IndexSubTableFormat2::Builder::CreateBuilder(
+          data, index_sub_table_offset, first_glyph_index, last_glyph_index);
+    case 3:
+      return IndexSubTableFormat3::Builder::CreateBuilder(
+          data, index_sub_table_offset, first_glyph_index, last_glyph_index);
+    case 4:
+      return IndexSubTableFormat4::Builder::CreateBuilder(
+          data, index_sub_table_offset, first_glyph_index, last_glyph_index);
+    case 5:
+      return IndexSubTableFormat5::Builder::CreateBuilder(
+          data, index_sub_table_offset, first_glyph_index, last_glyph_index);
+    default:
+      // Unknown format and unable to process.
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IllegalArgumentException("Invalid Index Subtable Format");
+#endif
+      break;
+  }
+  return NULL;
+}
+
+CALLER_ATTACH
+FontDataTable* IndexSubTable::Builder::SubBuildTable(ReadableFontData* data) {
+  UNREFERENCED_PARAMETER(data);
+  return NULL;
+}
+
+void IndexSubTable::Builder::SubDataSet() {
+  // NOP
+}
+
+int32_t IndexSubTable::Builder::SubDataSizeToSerialize() {
+  return 0;
+}
+
+bool IndexSubTable::Builder::SubReadyToSerialize() {
+  return false;
+}
+
+int32_t IndexSubTable::Builder::SubSerialize(WritableFontData* new_data) {
+  UNREFERENCED_PARAMETER(new_data);
+  return 0;
+}
+
+IndexSubTable::Builder::Builder(int32_t data_size, int32_t index_format)
+    : SubTable::Builder(data_size),
+      first_glyph_index_(0),
+      last_glyph_index_(0),
+      index_format_(index_format),
+      image_format_(0),
+      image_data_offset_(0) {
+}
+
+IndexSubTable::Builder::Builder(int32_t index_format,
+                                int32_t image_format,
+                                int32_t image_data_offset,
+                                int32_t data_size)
+    : SubTable::Builder(data_size),
+      first_glyph_index_(0),
+      last_glyph_index_(0),
+      index_format_(index_format),
+      image_format_(image_format),
+      image_data_offset_(image_data_offset) {
+}
+
+IndexSubTable::Builder::Builder(WritableFontData* data,
+                                int32_t first_glyph_index,
+                                int32_t last_glyph_index)
+    : SubTable::Builder(data),
+      first_glyph_index_(first_glyph_index),
+      last_glyph_index_(last_glyph_index) {
+  Initialize(data);
+}
+
+IndexSubTable::Builder::Builder(ReadableFontData* data,
+                                int32_t first_glyph_index,
+                                int32_t last_glyph_index)
+    : SubTable::Builder(data),
+      first_glyph_index_(first_glyph_index),
+      last_glyph_index_(last_glyph_index) {
+  Initialize(data);
+}
+
+int32_t IndexSubTable::Builder::CheckGlyphRange(int32_t glyph_id) {
+  return IndexSubTable::CheckGlyphRange(glyph_id,
+                                        first_glyph_index(),
+                                        last_glyph_index());
+}
+
+int32_t IndexSubTable::Builder::SerializeIndexSubHeader(
+    WritableFontData* data) {
+  int32_t size =
+      data->WriteUShort(EblcTable::Offset::kIndexSubHeader_indexFormat,
+                        index_format());
+  size += data->WriteUShort(EblcTable::Offset::kIndexSubHeader_imageFormat,
+                            image_format());
+  size += data->WriteULong(EblcTable::Offset::kIndexSubHeader_imageDataOffset,
+                           image_data_offset());
+  return size;
+}
+
+void IndexSubTable::Builder::Initialize(ReadableFontData* data) {
+  index_format_ =
+      data->ReadUShort(EblcTable::Offset::kIndexSubHeader_indexFormat);
+  image_format_ =
+      data->ReadUShort(EblcTable::Offset::kIndexSubHeader_imageFormat);
+  image_data_offset_ =
+      data->ReadULongAsInt(EblcTable::Offset::kIndexSubHeader_imageDataOffset);
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table.h b/cpp/src/sfntly/table/bitmap/index_sub_table.h
new file mode 100644
index 0000000..6d27129
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_
+
+#include <vector>
+
+#include "sfntly/port/java_iterator.h"
+#include "sfntly/table/subtable.h"
+#include "sfntly/table/bitmap/bitmap_glyph_info.h"
+
+namespace sfntly {
+
+class IndexSubTable : public SubTable {
+ public:
+  struct Format {
+    enum {
+      FORMAT_1 = 1,
+      FORMAT_2 = 2,
+      FORMAT_3 = 3,
+      FORMAT_4 = 4,
+      FORMAT_5 = 5,
+    };
+  };
+
+  class Builder : public SubTable::Builder {
+   public:
+    virtual ~Builder();
+
+    void Revert();
+
+    int32_t index_format() { return index_format_; }
+    int32_t first_glyph_index() { return first_glyph_index_; }
+    void set_first_glyph_index(int32_t v) { first_glyph_index_ = v; }
+    int32_t last_glyph_index() { return last_glyph_index_; }
+    void set_last_glyph_index(int32_t v) { last_glyph_index_ = v; }
+    int32_t image_format() { return image_format_; }
+    void set_image_format(int32_t v) { image_format_ = v; }
+    int32_t image_data_offset() { return image_data_offset_; }
+    void set_image_data_offset(int32_t v) { image_data_offset_ = v; }
+
+    virtual int32_t NumGlyphs() = 0;
+
+    // Gets the glyph info for the specified glyph id.
+    // @param glyphId the glyph id to look up
+    // @return the glyph info
+    CALLER_ATTACH virtual BitmapGlyphInfo* GlyphInfo(int32_t glyph_id);
+
+    // Gets the full offset of the glyph within the EBDT table.
+    // @param glyphId the glyph id
+    // @return the glyph offset
+    virtual int32_t GlyphOffset(int32_t glyph_id);
+
+    // Gets the offset of the glyph relative to the block for this index
+    // subtable.
+    // @param glyphId the glyph id
+    // @return the glyph offset
+    virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0;
+
+    // Gets the length of the glyph within the EBDT table.
+    // @param glyphId the glyph id
+    // @return the glyph offset
+    virtual int32_t GlyphLength(int32_t glyph_id) = 0;
+
+    // Note: renamed from java iterator()
+    CALLER_ATTACH virtual Iterator<BitmapGlyphInfo, IndexSubTable::Builder>*
+        GetIterator() = 0;
+
+    // Static instantiation function.
+    static CALLER_ATTACH Builder* CreateBuilder(int32_t index_format);
+    static CALLER_ATTACH Builder*
+        CreateBuilder(ReadableFontData* data,
+                      int32_t offset_to_index_sub_table_array,
+                      int32_t array_index);
+
+    // The following methods will never be called but they need to be here to
+    // allow the BitmapSizeTable to see these methods through an abstract
+    // reference.
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+   protected:
+    Builder(int32_t data_size, int32_t index_format);
+    Builder(int32_t index_format,
+            int32_t image_format,
+            int32_t image_data_offset,
+            int32_t data_size);
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+
+    // Checks that the glyph id is within the correct range. If it returns the
+    // offset of the glyph id from the start of the range.
+    // @param glyphId
+    // @return the offset of the glyphId from the start of the glyph range
+    // @throws IndexOutOfBoundsException if the glyph id is not within the
+    //         correct range
+    int32_t CheckGlyphRange(int32_t glyph_id);
+    int32_t SerializeIndexSubHeader(WritableFontData* data);
+
+   private:
+    void Initialize(ReadableFontData* data);
+
+    int32_t first_glyph_index_;
+    int32_t last_glyph_index_;
+    int32_t index_format_;
+    int32_t image_format_;
+    int32_t image_data_offset_;
+  };
+
+  int32_t index_format() { return index_format_; }
+  int32_t first_glyph_index() { return first_glyph_index_; }
+  int32_t last_glyph_index() { return last_glyph_index_; }
+  int32_t image_format() { return image_format_; }
+  int32_t image_data_offset() { return image_data_offset_; }
+
+  CALLER_ATTACH BitmapGlyphInfo* GlyphInfo(int32_t glyph_id);
+  virtual int32_t GlyphOffset(int32_t glyph_id);
+  virtual int32_t GlyphStartOffset(int32_t glyph_id) = 0;
+  virtual int32_t GlyphLength(int32_t glyph_id) = 0;
+  virtual int32_t NumGlyphs() = 0;
+
+  static CALLER_ATTACH IndexSubTable*
+      CreateIndexSubTable(ReadableFontData* data,
+                          int32_t offset_to_index_sub_table_array,
+                          int32_t array_index);
+
+ protected:
+  // Note: the constructor does not implement offset/length form provided in
+  //       Java to avoid heavy lifting in constructors.  Callers to call
+  //       GetDataLength() static method of the derived class to get proper
+  //       length and slice ahead.
+  IndexSubTable(ReadableFontData* data,
+                int32_t first_glyph_index,
+                int32_t last_glyph_index);
+
+  int32_t CheckGlyphRange(int32_t glyph_id);
+  static int32_t CheckGlyphRange(int32_t glyph_id,
+                                 int32_t first_glyph_id,
+                                 int32_t last_glyph_id);
+
+ private:
+  int32_t first_glyph_index_;
+  int32_t last_glyph_index_;
+  int32_t index_format_;
+  int32_t image_format_;
+  int32_t image_data_offset_;
+};
+typedef Ptr<IndexSubTable> IndexSubTablePtr;
+typedef std::vector<IndexSubTablePtr> IndexSubTableList;
+typedef Ptr<IndexSubTable::Builder> IndexSubTableBuilderPtr;
+typedef std::vector<IndexSubTableBuilderPtr> IndexSubTableBuilderList;
+typedef Iterator<BitmapGlyphInfo, IndexSubTable::Builder> BitmapGlyphInfoIter;
+typedef Ptr<BitmapGlyphInfoIter> BitmapGlyphInfoIterPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_H_
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format1.cc b/cpp/src/sfntly/table/bitmap/index_sub_table_format1.cc
new file mode 100644
index 0000000..5199e18
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format1.cc
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/index_sub_table_format1.h"
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTableFormat1 class
+ ******************************************************************************/
+// static
+int32_t IndexSubTableFormat1::GetDataLength(ReadableFontData* data,
+                                            int32_t offset,
+                                            int32_t first,
+                                            int32_t last) {
+  UNREFERENCED_PARAMETER(data);
+  UNREFERENCED_PARAMETER(offset);
+  return (last - first + 1 + 1) * DataSize::kULONG;
+}
+
+IndexSubTableFormat1::~IndexSubTableFormat1() {
+}
+
+int32_t IndexSubTableFormat1::NumGlyphs() {
+  return last_glyph_index() - first_glyph_index() + 1;
+}
+
+int32_t IndexSubTableFormat1::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return Loca(loca);
+}
+
+int32_t IndexSubTableFormat1::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return Loca(loca + 1) - Loca(loca);
+}
+
+IndexSubTableFormat1::IndexSubTableFormat1(ReadableFontData* data,
+                                           int32_t first_glyph_index,
+                                           int32_t last_glyph_index)
+    : IndexSubTable(data, first_glyph_index, last_glyph_index) {
+}
+
+int32_t IndexSubTableFormat1::Loca(int32_t loca) {
+  return image_data_offset() +
+         data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable1_offsetArray +
+                               loca * DataSize::kULONG);
+}
+
+/******************************************************************************
+ * IndexSubTableFormat1::Builder class
+ ******************************************************************************/
+IndexSubTableFormat1::Builder::~Builder() {
+}
+
+int32_t IndexSubTableFormat1::Builder::NumGlyphs() {
+  return GetOffsetArray()->size() - 1;
+}
+
+int32_t IndexSubTableFormat1::Builder::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return 0;
+  }
+  IntegerList* offset_array = GetOffsetArray();
+  return offset_array->at(loca + 1) - offset_array->at(loca);
+}
+
+int32_t IndexSubTableFormat1::Builder::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return GetOffsetArray()->at(loca);
+}
+
+CALLER_ATTACH IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator*
+    IndexSubTableFormat1::Builder::GetIterator() {
+  Ptr<IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator> it =
+      new IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator(this);
+  return it.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat1::Builder*
+IndexSubTableFormat1::Builder::CreateBuilder() {
+  IndexSubTableFormat1BuilderPtr output = new IndexSubTableFormat1::Builder();
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat1::Builder*
+IndexSubTableFormat1::Builder::CreateBuilder(ReadableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  ReadableFontDataPtr new_data;
+  new_data.Attach(down_cast<ReadableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  if (new_data == NULL) {
+    return NULL;
+  }
+  IndexSubTableFormat1BuilderPtr output =
+      new IndexSubTableFormat1::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+
+// static
+CALLER_ATTACH IndexSubTableFormat1::Builder*
+IndexSubTableFormat1::Builder::CreateBuilder(WritableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  WritableFontDataPtr new_data;
+  new_data.Attach(down_cast<WritableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  IndexSubTableFormat1BuilderPtr output =
+      new IndexSubTableFormat1::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+CALLER_ATTACH FontDataTable* IndexSubTableFormat1::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  IndexSubTableFormat1Ptr output = new IndexSubTableFormat1(
+      data, first_glyph_index(), last_glyph_index());
+  return output.Detach();
+}
+
+void IndexSubTableFormat1::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t IndexSubTableFormat1::Builder::SubDataSizeToSerialize() {
+  if (offset_array_.empty()) {
+    return InternalReadData()->Length();
+  }
+  return EblcTable::Offset::kIndexSubHeaderLength +
+         offset_array_.size() * DataSize::kULONG;
+}
+
+bool IndexSubTableFormat1::Builder::SubReadyToSerialize() {
+  if (!offset_array_.empty()) {
+    return true;
+  }
+  return false;
+}
+
+int32_t IndexSubTableFormat1::Builder::SubSerialize(
+    WritableFontData* new_data) {
+  int32_t size = SerializeIndexSubHeader(new_data);
+  if (!model_changed()) {
+    if (InternalReadData() == NULL) {
+      return size;
+    }
+    ReadableFontDataPtr source;
+    WritableFontDataPtr target;
+    source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
+        EblcTable::Offset::kIndexSubTable1_offsetArray)));
+    target.Attach(down_cast<WritableFontData*>(new_data->Slice(
+        EblcTable::Offset::kIndexSubTable1_offsetArray)));
+    size += source->CopyTo(target);
+  } else {
+    for (IntegerList::iterator b = GetOffsetArray()->begin(),
+                               e = GetOffsetArray()->end(); b != e; b++) {
+      size += new_data->WriteLong(size, *b);
+    }
+  }
+  return size;
+}
+
+IntegerList* IndexSubTableFormat1::Builder::OffsetArray() {
+  return GetOffsetArray();
+}
+
+void IndexSubTableFormat1::Builder::SetOffsetArray(
+    const IntegerList& offset_array) {
+  offset_array_.clear();
+  offset_array_ = offset_array;
+  set_model_changed();
+}
+
+void IndexSubTableFormat1::Builder::Revert() {
+  offset_array_.clear();
+  IndexSubTable::Builder::Revert();
+}
+
+IndexSubTableFormat1::Builder::Builder()
+    : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable1_builderDataSize,
+                             IndexSubTable::Format::FORMAT_1) {
+}
+
+IndexSubTableFormat1::Builder::Builder(WritableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IndexSubTableFormat1::Builder::Builder(ReadableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IntegerList* IndexSubTableFormat1::Builder::GetOffsetArray() {
+  if (offset_array_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &offset_array_;
+}
+
+void IndexSubTableFormat1::Builder::Initialize(ReadableFontData* data) {
+  offset_array_.clear();
+  if (data) {
+    int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1;
+    for (int32_t i = 0; i < num_offsets; ++i) {
+      offset_array_.push_back(data->ReadULongAsInt(
+          EblcTable::Offset::kIndexSubTable1_offsetArray +
+          i * DataSize::kULONG));
+    }
+  }
+}
+
+// static
+int32_t IndexSubTableFormat1::Builder::DataLength(
+    ReadableFontData* data,
+    int32_t index_sub_table_offset,
+    int32_t first_glyph_index,
+    int32_t last_glyph_index) {
+  UNREFERENCED_PARAMETER(data);
+  UNREFERENCED_PARAMETER(index_sub_table_offset);
+  return EblcTable::Offset::kIndexSubHeaderLength +
+         (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kULONG;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    IndexSubTableFormat1::Builder* container)
+    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat1::Builder,
+                  IndexSubTable::Builder>(container) {
+  glyph_id_ = container->first_glyph_index();
+}
+
+bool IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (glyph_id_ <= container()->last_glyph_index()) {
+    return true;
+  }
+  return false;
+}
+
+CALLER_ATTACH BitmapGlyphInfo*
+IndexSubTableFormat1::Builder::BitmapGlyphInfoIterator::Next() {
+  BitmapGlyphInfoPtr output;
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  output = new BitmapGlyphInfo(glyph_id_,
+                               container()->image_data_offset(),
+                               container()->GlyphStartOffset(glyph_id_),
+                               container()->GlyphLength(glyph_id_),
+                               container()->image_format());
+  glyph_id_++;
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format1.h b/cpp/src/sfntly/table/bitmap/index_sub_table_format1.h
new file mode 100644
index 0000000..33171c1
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format1.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_
+
+#include "sfntly/port/java_iterator.h"
+#include "sfntly/table/bitmap/index_sub_table.h"
+
+namespace sfntly {
+// Format 1 Index Subtable Entry.
+class IndexSubTableFormat1 : public IndexSubTable,
+                             public RefCounted<IndexSubTableFormat1> {
+ public:
+  class Builder : public IndexSubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator
+        : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      int32_t glyph_id_;
+    };
+
+    virtual ~Builder();
+    virtual int32_t NumGlyphs();
+    virtual int32_t GlyphLength(int32_t glyph_id);
+    virtual int32_t GlyphStartOffset(int32_t glyph_id);
+    CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    IntegerList* OffsetArray();
+    void SetOffsetArray(const IntegerList& offset_array);
+    CALLER_ATTACH BitmapGlyphInfoIter* Iterator();
+
+    static CALLER_ATTACH Builder* CreateBuilder();
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+
+   protected:
+    void Revert();
+
+   private:
+    Builder();
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    IntegerList* GetOffsetArray();
+    void Initialize(ReadableFontData* data);
+
+    static int32_t DataLength(ReadableFontData* data,
+                              int32_t index_sub_table_offset,
+                              int32_t first_glyph_index,
+                              int32_t last_glyph_index);
+
+    IntegerList offset_array_;
+  };
+
+  virtual ~IndexSubTableFormat1();
+
+  virtual int32_t NumGlyphs();
+  virtual int32_t GlyphStartOffset(int32_t glyph_id);
+  virtual int32_t GlyphLength(int32_t glyph_id);
+
+  static int32_t GetDataLength(ReadableFontData* data,
+                               int32_t offset,
+                               int32_t first,
+                               int32_t last);
+
+ private:
+  IndexSubTableFormat1(ReadableFontData* data,
+                       int32_t first_glyph_index,
+                       int32_t last_glyph_index);
+  int32_t Loca(int32_t loca_index);
+
+  friend class Builder;
+};
+typedef Ptr<IndexSubTableFormat1> IndexSubTableFormat1Ptr;
+typedef Ptr<IndexSubTableFormat1::Builder> IndexSubTableFormat1BuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format2.cc b/cpp/src/sfntly/table/bitmap/index_sub_table_format2.cc
new file mode 100644
index 0000000..ce73e9b
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format2.cc
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/index_sub_table_format2.h"
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTableFormat2 class
+ ******************************************************************************/
+IndexSubTableFormat2::~IndexSubTableFormat2() {
+}
+
+int32_t IndexSubTableFormat2::ImageSize() {
+  return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize);
+}
+
+CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat2::BigMetrics() {
+  ReadableFontDataPtr slice;
+  slice.Attach(down_cast<ReadableFontData*>(
+      data_->Slice(EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics,
+                   BigGlyphMetrics::Offset::kMetricsLength)));
+  BigGlyphMetricsPtr output = new BigGlyphMetrics(slice);
+  return output.Detach();
+}
+
+int32_t IndexSubTableFormat2::NumGlyphs() {
+  return last_glyph_index() - first_glyph_index() + 1;
+}
+
+int32_t IndexSubTableFormat2::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return loca * image_size_;
+}
+
+int32_t IndexSubTableFormat2::GlyphLength(int32_t glyph_id) {
+  if (CheckGlyphRange(glyph_id) == -1) {
+    return 0;
+  }
+  return image_size_;
+}
+
+IndexSubTableFormat2::IndexSubTableFormat2(ReadableFontData* data,
+                                           int32_t first,
+                                           int32_t last)
+    : IndexSubTable(data, first, last) {
+  image_size_ =
+      data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable2_imageSize);
+}
+
+/******************************************************************************
+ * IndexSubTableFormat2::Builder class
+ ******************************************************************************/
+IndexSubTableFormat2::Builder::~Builder() {
+}
+
+int32_t IndexSubTableFormat2::Builder::NumGlyphs() {
+  return last_glyph_index() - first_glyph_index() + 1;
+}
+
+int32_t IndexSubTableFormat2::Builder::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return loca * ImageSize();
+}
+
+int32_t IndexSubTableFormat2::Builder::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return 0;
+  }
+  return ImageSize();
+}
+
+CALLER_ATTACH IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator*
+    IndexSubTableFormat2::Builder::GetIterator() {
+  Ptr<IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator> it =
+      new IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator(this);
+  return it.Detach();
+}
+
+int32_t IndexSubTableFormat2::Builder::ImageSize() {
+  return InternalReadData()->ReadULongAsInt(
+      EblcTable::Offset::kIndexSubTable2_imageSize);
+}
+
+void IndexSubTableFormat2::Builder::SetImageSize(int32_t image_size) {
+  InternalWriteData()->WriteULong(EblcTable::Offset::kIndexSubTable2_imageSize,
+                                  image_size);
+}
+
+BigGlyphMetrics::Builder* IndexSubTableFormat2::Builder::BigMetrics() {
+  if (metrics_ == NULL) {
+    WritableFontDataPtr data;
+    data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice(
+        EblcTable::Offset::kIndexSubTable2_bigGlyphMetrics,
+        BigGlyphMetrics::Offset::kMetricsLength)));
+    metrics_ = new BigGlyphMetrics::Builder(data);
+  }
+  return metrics_;
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat2::Builder*
+IndexSubTableFormat2::Builder::CreateBuilder() {
+  IndexSubTableFormat2BuilderPtr output = new IndexSubTableFormat2::Builder();
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat2::Builder*
+IndexSubTableFormat2::Builder::CreateBuilder(ReadableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  ReadableFontDataPtr new_data;
+  new_data.Attach(down_cast<ReadableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  if (new_data == NULL) {
+    return NULL;
+  }
+  IndexSubTableFormat2BuilderPtr output =
+      new IndexSubTableFormat2::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat2::Builder*
+IndexSubTableFormat2::Builder::CreateBuilder(WritableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  WritableFontDataPtr new_data;
+  new_data.Attach(down_cast<WritableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  IndexSubTableFormat2BuilderPtr output =
+      new IndexSubTableFormat2::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+CALLER_ATTACH FontDataTable* IndexSubTableFormat2::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  IndexSubTableFormat2Ptr output = new IndexSubTableFormat2(
+      data, first_glyph_index(), last_glyph_index());
+  return output.Detach();
+}
+
+void IndexSubTableFormat2::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t IndexSubTableFormat2::Builder::SubDataSizeToSerialize() {
+  return EblcTable::Offset::kIndexSubTable2Length;
+}
+
+bool IndexSubTableFormat2::Builder::SubReadyToSerialize() {
+  return true;
+}
+
+int32_t IndexSubTableFormat2::Builder::SubSerialize(
+    WritableFontData* new_data) {
+  int32_t size = SerializeIndexSubHeader(new_data);
+  if (metrics_ == NULL) {
+    ReadableFontDataPtr source;
+    WritableFontDataPtr target;
+    source.Attach(down_cast<ReadableFontData*>(
+        InternalReadData()->Slice(size)));
+    target.Attach(down_cast<WritableFontData*>(new_data->Slice(size)));
+    size += source->CopyTo(target);
+  } else {
+    WritableFontDataPtr slice;
+    size += new_data->WriteLong(EblcTable::Offset::kIndexSubTable2_imageSize,
+                                ImageSize());
+    slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size)));
+    size += metrics_->SubSerialize(slice);
+  }
+  return size;
+}
+
+IndexSubTableFormat2::Builder::Builder()
+    : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize,
+                             IndexSubTable::Format::FORMAT_2) {
+  metrics_.Attach(BigGlyphMetrics::Builder::CreateBuilder());
+}
+
+IndexSubTableFormat2::Builder::Builder(WritableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IndexSubTableFormat2::Builder::Builder(ReadableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+// static
+int32_t IndexSubTableFormat2::Builder::DataLength(
+    ReadableFontData* data,
+    int32_t index_sub_table_offset,
+    int32_t first_glyph_index,
+    int32_t last_glyph_index) {
+  UNREFERENCED_PARAMETER(data);
+  UNREFERENCED_PARAMETER(index_sub_table_offset);
+  UNREFERENCED_PARAMETER(first_glyph_index);
+  UNREFERENCED_PARAMETER(last_glyph_index);
+  return EblcTable::Offset::kIndexSubTable2Length;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    IndexSubTableFormat2::Builder* container)
+    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat2::Builder,
+                  IndexSubTable::Builder>(container) {
+  glyph_id_ = container->first_glyph_index();
+}
+
+bool IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (glyph_id_ <= container()->last_glyph_index()) {
+    return true;
+  }
+  return false;
+}
+
+CALLER_ATTACH BitmapGlyphInfo*
+IndexSubTableFormat2::Builder::BitmapGlyphInfoIterator::Next() {
+  BitmapGlyphInfoPtr output;
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  output = new BitmapGlyphInfo(glyph_id_,
+                               container()->image_data_offset(),
+                               container()->GlyphStartOffset(glyph_id_),
+                               container()->GlyphLength(glyph_id_),
+                               container()->image_format());
+  glyph_id_++;
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format2.h b/cpp/src/sfntly/table/bitmap/index_sub_table_format2.h
new file mode 100644
index 0000000..784e8a3
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format2.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT2_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT2_H_
+
+#include "sfntly/table/bitmap/index_sub_table.h"
+#include "sfntly/table/bitmap/big_glyph_metrics.h"
+
+namespace sfntly {
+// Format 2 Index Subtable Entry.
+class IndexSubTableFormat2 : public IndexSubTable,
+                             public RefCounted<IndexSubTableFormat2> {
+ public:
+  class Builder : public IndexSubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator
+        : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      int32_t glyph_id_;
+    };
+
+    virtual ~Builder();
+    virtual int32_t NumGlyphs();
+    virtual int32_t GlyphStartOffset(int32_t glyph_id);
+    virtual int32_t GlyphLength(int32_t glyph_id);
+    CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    int32_t ImageSize();
+    void SetImageSize(int32_t image_size);
+    BigGlyphMetrics::Builder* BigMetrics();
+
+    static CALLER_ATTACH Builder* CreateBuilder();
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+   private:
+    Builder();
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+
+    static int32_t DataLength(ReadableFontData* data,
+                              int32_t index_sub_table_offset,
+                              int32_t first_glyph_index,
+                              int32_t last_glyph_index);
+
+    BigGlyphMetricsBuilderPtr metrics_;
+  };
+
+  virtual ~IndexSubTableFormat2();
+
+  int32_t ImageSize();
+  CALLER_ATTACH BigGlyphMetrics* BigMetrics();
+
+  virtual int32_t NumGlyphs();
+  virtual int32_t GlyphStartOffset(int32_t glyph_id);
+  virtual int32_t GlyphLength(int32_t glyph_id);
+
+ private:
+  IndexSubTableFormat2(ReadableFontData* data, int32_t first, int32_t last);
+
+  int32_t image_size_;
+  friend class Builder;
+};
+typedef Ptr<IndexSubTableFormat2> IndexSubTableFormat2Ptr;
+typedef Ptr<IndexSubTableFormat2::Builder> IndexSubTableFormat2BuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT1_H_
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format3.cc b/cpp/src/sfntly/table/bitmap/index_sub_table_format3.cc
new file mode 100644
index 0000000..e2679b7
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format3.cc
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/index_sub_table_format3.h"
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTableFormat3 class
+ ******************************************************************************/
+IndexSubTableFormat3::~IndexSubTableFormat3() {
+}
+
+int32_t IndexSubTableFormat3::NumGlyphs() {
+  return last_glyph_index() - first_glyph_index() + 1;
+}
+
+int32_t IndexSubTableFormat3::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca != -1) {
+    return Loca(loca);
+  }
+  return -1;
+}
+
+int32_t IndexSubTableFormat3::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca != -1) {
+    return Loca(glyph_id + 1) - Loca(glyph_id);
+  }
+  return 0;
+}
+
+// static
+int32_t IndexSubTableFormat3::GetDataLength(ReadableFontData* data,
+                                            int32_t offset,
+                                            int32_t first,
+                                            int32_t last) {
+  UNREFERENCED_PARAMETER(data);
+  UNREFERENCED_PARAMETER(offset);
+  return (last - first + 1 + 1) * DataSize::kUSHORT;
+}
+
+IndexSubTableFormat3::IndexSubTableFormat3(ReadableFontData* data,
+                                           int32_t first_glyph_index,
+                                           int32_t last_glyph_index)
+    : IndexSubTable(data, first_glyph_index, last_glyph_index) {
+}
+
+int32_t IndexSubTableFormat3::Loca(int32_t loca) {
+  int32_t read_offset =
+      data_->ReadUShort(EblcTable::Offset::kIndexSubTable3_offsetArray +
+                        loca * DataSize::kUSHORT);
+  return read_offset;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat3::Builder class
+ ******************************************************************************/
+IndexSubTableFormat3::Builder::~Builder() {
+}
+
+int32_t IndexSubTableFormat3::Builder::NumGlyphs() {
+  return GetOffsetArray()->size() - 1;
+}
+
+int32_t IndexSubTableFormat3::Builder::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  return GetOffsetArray()->at(loca);
+}
+
+int32_t IndexSubTableFormat3::Builder::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return 0;
+  }
+  IntegerList* offset_array = GetOffsetArray();
+  return offset_array->at(loca + 1) - offset_array->at(loca);
+}
+
+CALLER_ATTACH IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator*
+    IndexSubTableFormat3::Builder::GetIterator() {
+  Ptr<IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator> it =
+      new IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator(this);
+  return it.Detach();
+}
+
+void IndexSubTableFormat3::Builder::Revert() {
+  offset_array_.clear();
+  IndexSubTable::Builder::Revert();
+}
+
+void IndexSubTableFormat3::Builder::SetOffsetArray(
+    const IntegerList& offset_array) {
+  offset_array_.clear();
+  offset_array_ = offset_array;
+  set_model_changed();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat3::Builder*
+IndexSubTableFormat3::Builder::CreateBuilder() {
+  IndexSubTableFormat3BuilderPtr output = new IndexSubTableFormat3::Builder();
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat3::Builder*
+IndexSubTableFormat3::Builder::CreateBuilder(ReadableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  ReadableFontDataPtr new_data;
+  new_data.Attach(down_cast<ReadableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  if (new_data == NULL) {
+    return NULL;
+  }
+  IndexSubTableFormat3BuilderPtr output =
+      new IndexSubTableFormat3::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat3::Builder*
+IndexSubTableFormat3::Builder::CreateBuilder(WritableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  WritableFontDataPtr new_data;
+  new_data.Attach(down_cast<WritableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  IndexSubTableFormat3BuilderPtr output =
+      new IndexSubTableFormat3::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+CALLER_ATTACH FontDataTable* IndexSubTableFormat3::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  IndexSubTableFormat3Ptr output = new IndexSubTableFormat3(
+      data, first_glyph_index(), last_glyph_index());
+  return output.Detach();
+}
+
+void IndexSubTableFormat3::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t IndexSubTableFormat3::Builder::SubDataSizeToSerialize() {
+  if (offset_array_.empty()) {
+    return InternalReadData()->Length();
+  }
+  return EblcTable::Offset::kIndexSubHeaderLength +
+         offset_array_.size() * DataSize::kULONG;
+}
+
+bool IndexSubTableFormat3::Builder::SubReadyToSerialize() {
+  if (!offset_array_.empty()) {
+    return true;
+  }
+  return false;
+}
+
+int32_t IndexSubTableFormat3::Builder::SubSerialize(
+    WritableFontData* new_data) {
+  int32_t size = SerializeIndexSubHeader(new_data);
+  if (!model_changed()) {
+    if (InternalReadData() == NULL) {
+      return size;
+    }
+    ReadableFontDataPtr source;
+    WritableFontDataPtr target;
+    source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
+        EblcTable::Offset::kIndexSubTable3_offsetArray)));
+    target.Attach(down_cast<WritableFontData*>(new_data->Slice(
+        EblcTable::Offset::kIndexSubTable3_offsetArray)));
+    size += source->CopyTo(target);
+  } else {
+    for (IntegerList::iterator b = GetOffsetArray()->begin(),
+                               e = GetOffsetArray()->end(); b != e; b++) {
+      size += new_data->WriteUShort(size, *b);
+    }
+  }
+  return size;
+}
+
+IndexSubTableFormat3::Builder::Builder()
+    : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable3_builderDataSize,
+                             IndexSubTable::Format::FORMAT_3) {
+}
+
+IndexSubTableFormat3::Builder::Builder(WritableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IndexSubTableFormat3::Builder::Builder(ReadableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IntegerList* IndexSubTableFormat3::Builder::GetOffsetArray() {
+  if (offset_array_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &offset_array_;
+}
+
+void IndexSubTableFormat3::Builder::Initialize(ReadableFontData* data) {
+  offset_array_.clear();
+  if (data) {
+    int32_t num_offsets = (last_glyph_index() - first_glyph_index() + 1) + 1;
+    for (int32_t i = 0; i < num_offsets; ++i) {
+      offset_array_.push_back(data->ReadUShort(
+         EblcTable::Offset::kIndexSubTable3_offsetArray +
+         i * DataSize::kUSHORT));
+    }
+  }
+}
+
+// static
+int32_t IndexSubTableFormat3::Builder::DataLength(
+    ReadableFontData* data,
+    int32_t index_sub_table_offset,
+    int32_t first_glyph_index,
+    int32_t last_glyph_index) {
+  UNREFERENCED_PARAMETER(data);
+  UNREFERENCED_PARAMETER(index_sub_table_offset);
+  return EblcTable::Offset::kIndexSubHeaderLength +
+         (last_glyph_index - first_glyph_index + 1 + 1) * DataSize::kUSHORT;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    IndexSubTableFormat3::Builder* container)
+    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat3::Builder,
+                  IndexSubTable::Builder>(container) {
+  glyph_id_ = container->first_glyph_index();
+}
+
+bool IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (glyph_id_ <= container()->last_glyph_index()) {
+    return true;
+  }
+  return false;
+}
+
+CALLER_ATTACH BitmapGlyphInfo*
+IndexSubTableFormat3::Builder::BitmapGlyphInfoIterator::Next() {
+  BitmapGlyphInfoPtr output;
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  output = new BitmapGlyphInfo(glyph_id_,
+                               container()->image_data_offset(),
+                               container()->GlyphStartOffset(glyph_id_),
+                               container()->GlyphLength(glyph_id_),
+                               container()->image_format());
+  glyph_id_++;
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format3.h b/cpp/src/sfntly/table/bitmap/index_sub_table_format3.h
new file mode 100644
index 0000000..d71f857
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format3.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_
+
+#include "sfntly/table/bitmap/index_sub_table.h"
+
+namespace sfntly {
+// Format 3 Index Subtable Entry.
+class IndexSubTableFormat3 : public IndexSubTable,
+                             public RefCounted<IndexSubTableFormat3> {
+ public:
+  class Builder : public IndexSubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator
+        : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      int32_t glyph_id_;
+    };
+
+    virtual ~Builder();
+    virtual int32_t NumGlyphs();
+    virtual int32_t GlyphStartOffset(int32_t glyph_id);
+    virtual int32_t GlyphLength(int32_t glyph_id);
+    CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    void SetOffsetArray(const IntegerList& offset_array);
+
+    static CALLER_ATTACH Builder* CreateBuilder();
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+
+   protected:
+    void Revert();
+
+   private:
+    Builder();
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    IntegerList* GetOffsetArray();
+    void Initialize(ReadableFontData* data);
+
+    static int32_t DataLength(ReadableFontData* data,
+                              int32_t index_sub_table_offset,
+                              int32_t first_glyph_index,
+                              int32_t last_glyph_index);
+
+    IntegerList offset_array_;
+  };
+
+  virtual ~IndexSubTableFormat3();
+
+  virtual int32_t NumGlyphs();
+  virtual int32_t GlyphStartOffset(int32_t glyph_id);
+  virtual int32_t GlyphLength(int32_t glyph_id);
+
+  static int32_t GetDataLength(ReadableFontData* data,
+                               int32_t offset,
+                               int32_t first,
+                               int32_t last);
+
+ private:
+  IndexSubTableFormat3(ReadableFontData* data,
+                       int32_t first_glyph_index,
+                       int32_t last_glyph_index);
+  int32_t Loca(int32_t loca_index);
+
+  friend class Builder;
+};
+typedef Ptr<IndexSubTableFormat3> IndexSubTableFormat3Ptr;
+typedef Ptr<IndexSubTableFormat3::Builder> IndexSubTableFormat3BuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT3_H_
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format4.cc b/cpp/src/sfntly/table/bitmap/index_sub_table_format4.cc
new file mode 100644
index 0000000..5baa2a5
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format4.cc
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/index_sub_table_format4.h"
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTableFormat4 class
+ ******************************************************************************/
+IndexSubTableFormat4::~IndexSubTableFormat4() {
+}
+
+int32_t IndexSubTableFormat4::NumGlyphs() {
+  return IndexSubTableFormat4::NumGlyphs(data_, 0);
+}
+
+int32_t IndexSubTableFormat4::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  int32_t pair_index = FindCodeOffsetPair(glyph_id);
+  if (pair_index < 0) {
+    return -1;
+  }
+  return data_->ReadUShort(EblcTable::Offset::kIndexSubTable4_glyphArray +
+                           pair_index *
+                           EblcTable::Offset::kCodeOffsetPairLength +
+                           EblcTable::Offset::kCodeOffsetPair_offset);
+}
+
+int32_t IndexSubTableFormat4::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+
+  int32_t pair_index = FindCodeOffsetPair(glyph_id);
+  if (pair_index < 0) {
+    return -1;
+  }
+  return data_->ReadUShort(
+             EblcTable::Offset::kIndexSubTable4_glyphArray +
+             (pair_index + 1) * EblcTable::Offset::kCodeOffsetPairLength +
+             EblcTable::Offset::kCodeOffsetPair_offset) -
+         data_->ReadUShort(
+             EblcTable::Offset::kIndexSubTable4_glyphArray +
+             (pair_index) * EblcTable::Offset::kCodeOffsetPairLength +
+             EblcTable::Offset::kCodeOffsetPair_offset);
+}
+
+IndexSubTableFormat4::IndexSubTableFormat4(ReadableFontData* data,
+                                           int32_t first,
+                                           int32_t last)
+    : IndexSubTable(data, first, last) {
+}
+
+int32_t IndexSubTableFormat4::FindCodeOffsetPair(int32_t glyph_id) {
+  return data_->SearchUShort(EblcTable::Offset::kIndexSubTable4_glyphArray,
+                             EblcTable::Offset::kCodeOffsetPairLength,
+                             NumGlyphs(),
+                             glyph_id);
+}
+
+int32_t IndexSubTableFormat4::NumGlyphs(ReadableFontData* data,
+                                        int32_t table_offset) {
+  int32_t num_glyphs = data->ReadULongAsInt(table_offset +
+      EblcTable::Offset::kIndexSubTable4_numGlyphs);
+  return num_glyphs;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat4::CodeOffsetPair related class
+ ******************************************************************************/
+IndexSubTableFormat4::CodeOffsetPair::CodeOffsetPair(int32_t glyph_code,
+                                                     int32_t offset)
+    : glyph_code_(glyph_code), offset_(offset) {
+}
+
+IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder()
+    : CodeOffsetPair(0, 0) {
+}
+
+IndexSubTableFormat4::CodeOffsetPairBuilder::CodeOffsetPairBuilder(
+    int32_t glyph_code, int32_t offset)
+    : CodeOffsetPair(glyph_code, offset) {
+}
+
+bool IndexSubTableFormat4::CodeOffsetPairGlyphCodeComparator::operator()(
+    const CodeOffsetPair& lhs, const CodeOffsetPair& rhs) {
+  return lhs.glyph_code() < rhs.glyph_code();
+}
+
+/******************************************************************************
+ * IndexSubTableFormat4::Builder class
+ ******************************************************************************/
+IndexSubTableFormat4::Builder::~Builder() {
+}
+
+int32_t IndexSubTableFormat4::Builder::NumGlyphs() {
+  return GetOffsetArray()->size() - 1;
+}
+
+int32_t IndexSubTableFormat4::Builder::GlyphLength(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return 0;
+  }
+  int32_t pair_index = FindCodeOffsetPair(glyph_id);
+  if (pair_index == -1) {
+    return 0;
+  }
+  return GetOffsetArray()->at(pair_index + 1).offset() -
+         GetOffsetArray()->at(pair_index).offset();
+}
+
+int32_t IndexSubTableFormat4::Builder::GlyphStartOffset(int32_t glyph_id) {
+  int32_t loca = CheckGlyphRange(glyph_id);
+  if (loca == -1) {
+    return -1;
+  }
+  int32_t pair_index = FindCodeOffsetPair(glyph_id);
+  if (pair_index == -1) {
+    return -1;
+  }
+  return GetOffsetArray()->at(pair_index).offset();
+}
+
+CALLER_ATTACH IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator*
+    IndexSubTableFormat4::Builder::GetIterator() {
+  Ptr<IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator> it =
+      new IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator(this);
+  return it.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat4::Builder*
+IndexSubTableFormat4::Builder::CreateBuilder() {
+  IndexSubTableFormat4BuilderPtr output = new IndexSubTableFormat4::Builder();
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat4::Builder*
+IndexSubTableFormat4::Builder::CreateBuilder(ReadableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  ReadableFontDataPtr new_data;
+  new_data.Attach(down_cast<ReadableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  if (new_data == NULL) {
+    return NULL;
+  }
+  IndexSubTableFormat4BuilderPtr output =
+      new IndexSubTableFormat4::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat4::Builder*
+IndexSubTableFormat4::Builder::CreateBuilder(WritableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  WritableFontDataPtr new_data;
+  new_data.Attach(down_cast<WritableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  IndexSubTableFormat4BuilderPtr output =
+      new IndexSubTableFormat4::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+CALLER_ATTACH FontDataTable* IndexSubTableFormat4::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  IndexSubTableFormat4Ptr output = new IndexSubTableFormat4(
+      data, first_glyph_index(), last_glyph_index());
+  return output.Detach();
+}
+
+void IndexSubTableFormat4::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t IndexSubTableFormat4::Builder::SubDataSizeToSerialize() {
+  if (offset_pair_array_.empty()) {
+    return InternalReadData()->Length();
+  }
+  return EblcTable::Offset::kIndexSubHeaderLength + DataSize::kULONG +
+         GetOffsetArray()->size() *
+         EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength;
+}
+
+bool IndexSubTableFormat4::Builder::SubReadyToSerialize() {
+  if (!offset_pair_array_.empty()) {
+    return true;
+  }
+  return false;
+}
+
+int32_t IndexSubTableFormat4::Builder::SubSerialize(
+    WritableFontData* new_data) {
+  int32_t size = SerializeIndexSubHeader(new_data);
+  if (!model_changed()) {
+    if (InternalReadData() == NULL) {
+      return size;
+    }
+    ReadableFontDataPtr source;
+    WritableFontDataPtr target;
+    source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
+        EblcTable::Offset::kIndexSubTable4_glyphArray)));
+    target.Attach(down_cast<WritableFontData*>(new_data->Slice(
+        EblcTable::Offset::kIndexSubTable4_glyphArray)));
+    size += source->CopyTo(target);
+  } else {
+    size += new_data->WriteLong(size, offset_pair_array_.size() - 1);
+    for (std::vector<CodeOffsetPairBuilder>::iterator
+             b = GetOffsetArray()->begin(), e = GetOffsetArray()->end();
+             b != e; b++) {
+      size += new_data->WriteUShort(size, b->glyph_code());
+      size += new_data->WriteUShort(size, b->offset());
+    }
+  }
+  return size;
+}
+
+void IndexSubTableFormat4::Builder::Revert() {
+  offset_pair_array_.clear();
+  IndexSubTable::Builder::Revert();
+}
+
+void IndexSubTableFormat4::Builder::SetOffsetArray(
+    const std::vector<CodeOffsetPairBuilder>& pair_array) {
+  offset_pair_array_.clear();
+  offset_pair_array_ = pair_array;
+  set_model_changed();
+}
+
+IndexSubTableFormat4::Builder::Builder()
+  : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable4_builderDataSize,
+                           Format::FORMAT_4) {
+}
+
+IndexSubTableFormat4::Builder::Builder(WritableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IndexSubTableFormat4::Builder::Builder(ReadableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>*
+IndexSubTableFormat4::Builder::GetOffsetArray() {
+  if (offset_pair_array_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &offset_pair_array_;
+}
+
+void IndexSubTableFormat4::Builder::Initialize(ReadableFontData* data) {
+  offset_pair_array_.clear();
+  if (data) {
+    int32_t num_pairs = IndexSubTableFormat4::NumGlyphs(data, 0) + 1;
+    int32_t offset = EblcTable::Offset::kIndexSubTable4_glyphArray;
+    for (int32_t i = 0; i < num_pairs; ++i) {
+      int32_t glyph_code = data->ReadUShort(offset +
+          EblcTable::Offset::kIndexSubTable4_codeOffsetPair_glyphCode);
+      int32_t glyph_offset = data->ReadUShort(offset +
+          EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset);
+      offset += EblcTable::Offset::kIndexSubTable4_codeOffsetPairLength;
+      CodeOffsetPairBuilder pair_builder(glyph_code, glyph_offset);
+      offset_pair_array_.push_back(pair_builder);
+    }
+  }
+}
+
+int32_t IndexSubTableFormat4::Builder::FindCodeOffsetPair(int32_t glyph_id) {
+  std::vector<CodeOffsetPairBuilder>* pair_list = GetOffsetArray();
+  int32_t location = 0;
+  int32_t bottom = 0;
+  int32_t top = pair_list->size();
+  while (top != bottom) {
+    location = (top + bottom) / 2;
+    CodeOffsetPairBuilder* pair = &(pair_list->at(location));
+    if (glyph_id < pair->glyph_code()) {
+      // location is below current location
+      top = location;
+    } else if (glyph_id > pair->glyph_code()) {
+      // location is above current location
+      bottom = location + 1;
+    } else {
+      return location;
+    }
+  }
+  return -1;
+}
+
+// static
+int32_t IndexSubTableFormat4::Builder::DataLength(
+    ReadableFontData* data,
+    int32_t index_sub_table_offset,
+    int32_t first_glyph_index,
+    int32_t last_glyph_index) {
+  int32_t num_glyphs = IndexSubTableFormat4::NumGlyphs(data,
+                                                       index_sub_table_offset);
+  UNREFERENCED_PARAMETER(first_glyph_index);
+  UNREFERENCED_PARAMETER(last_glyph_index);
+  return EblcTable::Offset::kIndexSubTable4_glyphArray +
+         num_glyphs * EblcTable::Offset::kIndexSubTable4_codeOffsetPair_offset;
+}
+
+
+/******************************************************************************
+ * IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    IndexSubTableFormat4::Builder* container)
+    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat4::Builder,
+                  IndexSubTable::Builder>(container),
+      code_offset_pair_index_(0) {
+}
+
+bool IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (code_offset_pair_index_ <
+      (int32_t)(container()->GetOffsetArray()->size() - 1)) {
+    return true;
+  }
+  return false;
+}
+
+CALLER_ATTACH BitmapGlyphInfo*
+IndexSubTableFormat4::Builder::BitmapGlyphInfoIterator::Next() {
+  BitmapGlyphInfoPtr output;
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  std::vector<CodeOffsetPairBuilder>* offset_array =
+      container()->GetOffsetArray();
+  int32_t offset = offset_array->at(code_offset_pair_index_).offset();
+  int32_t next_offset = offset_array->at(code_offset_pair_index_ + 1).offset();
+  int32_t glyph_code = offset_array->at(code_offset_pair_index_).glyph_code();
+  output = new BitmapGlyphInfo(glyph_code,
+                               container()->image_data_offset(),
+                               offset,
+                               next_offset - offset,
+                               container()->image_format());
+  code_offset_pair_index_++;
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format4.h b/cpp/src/sfntly/table/bitmap/index_sub_table_format4.h
new file mode 100644
index 0000000..efd540f
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format4.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_
+
+#include "sfntly/table/bitmap/index_sub_table.h"
+
+namespace sfntly {
+
+class IndexSubTableFormat4 : public IndexSubTable,
+                             public RefCounted<IndexSubTableFormat4> {
+ public:
+  class CodeOffsetPair {
+   public:
+    int32_t glyph_code() const { return glyph_code_; }
+    int32_t offset() const { return offset_; }
+
+   protected:
+    CodeOffsetPair(int32_t glyph_code, int32_t offset);
+
+    // TODO(arthurhsu): C++ style guide prohibits protected members.
+    int32_t glyph_code_;
+    int32_t offset_;
+  };
+
+  class CodeOffsetPairBuilder : public CodeOffsetPair {
+   public:
+    CodeOffsetPairBuilder();
+    CodeOffsetPairBuilder(int32_t glyph_code, int32_t offset);
+    void set_glyph_code(int32_t v) { glyph_code_ = v; }
+    void set_offset(int32_t v) { offset_ = v; }
+  };
+
+  class CodeOffsetPairGlyphCodeComparator {
+   public:
+    bool operator()(const CodeOffsetPair& lhs, const CodeOffsetPair& rhs);
+  };
+
+  class Builder : public IndexSubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator
+        : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      int32_t code_offset_pair_index_;
+    };
+
+    virtual ~Builder();
+    virtual int32_t NumGlyphs();
+    virtual int32_t GlyphLength(int32_t glyph_id);
+    virtual int32_t GlyphStartOffset(int32_t glyph_id);
+    CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    void Revert();
+    void SetOffsetArray(const std::vector<CodeOffsetPairBuilder>& pair_array);
+
+    static CALLER_ATTACH Builder* CreateBuilder();
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+   private:
+    Builder();
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    std::vector<CodeOffsetPairBuilder>* GetOffsetArray();
+    void Initialize(ReadableFontData* data);
+    int32_t FindCodeOffsetPair(int32_t glyph_id);
+
+    static int32_t DataLength(ReadableFontData* data,
+                              int32_t index_sub_table_offset,
+                              int32_t first_glyph_index,
+                              int32_t last_glyph_index);
+
+    std::vector<CodeOffsetPairBuilder> offset_pair_array_;
+  };
+
+  virtual ~IndexSubTableFormat4();
+
+  virtual int32_t NumGlyphs();
+  virtual int32_t GlyphStartOffset(int32_t glyph_id);
+  virtual int32_t GlyphLength(int32_t glyph_id);
+
+ private:
+  IndexSubTableFormat4(ReadableFontData* data,
+                       int32_t first_glyph_index,
+                       int32_t last_glyph_index);
+
+  int32_t FindCodeOffsetPair(int32_t glyph_id);
+  static int32_t NumGlyphs(ReadableFontData* data, int32_t table_offset);
+
+  friend class Builder;
+};
+typedef Ptr<IndexSubTableFormat4> IndexSubTableFormat4Ptr;
+typedef Ptr<IndexSubTableFormat4::Builder> IndexSubTableFormat4BuilderPtr;
+typedef std::vector<IndexSubTableFormat4::CodeOffsetPairBuilder>
+            CodeOffsetPairBuilderList;
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT4_H_
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format5.cc b/cpp/src/sfntly/table/bitmap/index_sub_table_format5.cc
new file mode 100644
index 0000000..0ca21fe
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format5.cc
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/index_sub_table_format5.h"
+
+#include <algorithm>
+
+#include "sfntly/table/bitmap/eblc_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * IndexSubTableFormat5 class
+ ******************************************************************************/
+IndexSubTableFormat5::~IndexSubTableFormat5() {
+}
+
+int32_t IndexSubTableFormat5::NumGlyphs() {
+  return NumGlyphs(data_, 0);
+}
+
+int32_t IndexSubTableFormat5::GlyphStartOffset(int32_t glyph_id) {
+  int32_t check = CheckGlyphRange(glyph_id);
+  if (check == -1) {
+    return -1;
+  }
+  int32_t loca = ReadFontData()->SearchUShort(
+      EblcTable::Offset::kIndexSubTable5_glyphArray,
+      DataSize::kUSHORT,
+      NumGlyphs(),
+      glyph_id);
+  if (loca == -1) {
+    return loca;
+  }
+  return loca * ImageSize();
+}
+
+int32_t IndexSubTableFormat5::GlyphLength(int32_t glyph_id) {
+  int32_t check = CheckGlyphRange(glyph_id);
+  if (check == -1) {
+    return 0;
+  }
+  return image_size_;
+}
+
+int32_t IndexSubTableFormat5::ImageSize() {
+  return data_->ReadULongAsInt(EblcTable::Offset::kIndexSubTable5_imageSize);
+}
+
+CALLER_ATTACH BigGlyphMetrics* IndexSubTableFormat5::BigMetrics() {
+  ReadableFontDataPtr data;
+  data.Attach(down_cast<ReadableFontData*>(data_->Slice(
+      EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics,
+      BigGlyphMetrics::Offset::kMetricsLength)));
+  BigGlyphMetricsPtr output = new BigGlyphMetrics(data);
+  return output.Detach();
+}
+
+IndexSubTableFormat5::IndexSubTableFormat5(ReadableFontData* data,
+                                           int32_t first_glyph_index,
+                                           int32_t last_glyph_index)
+    : IndexSubTable(data, first_glyph_index, last_glyph_index) {
+  image_size_ = data_->ReadULongAsInt(
+      EblcTable::Offset::kIndexSubTable5_imageSize);
+}
+
+// static
+int32_t IndexSubTableFormat5::NumGlyphs(ReadableFontData* data,
+                                        int32_t table_offset) {
+  int32_t num_glyphs = data->ReadULongAsInt(table_offset +
+      EblcTable::Offset::kIndexSubTable5_numGlyphs);
+  return num_glyphs;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat5::Builder class
+ ******************************************************************************/
+IndexSubTableFormat5::Builder::~Builder() {
+}
+
+int32_t IndexSubTableFormat5::Builder::NumGlyphs() {
+  return GetGlyphArray()->size();
+}
+
+int32_t IndexSubTableFormat5::Builder::GlyphLength(int32_t glyph_id) {
+  UNREFERENCED_PARAMETER(glyph_id);
+  return ImageSize();
+}
+
+int32_t IndexSubTableFormat5::Builder::GlyphStartOffset(int32_t glyph_id) {
+  int32_t check = CheckGlyphRange(glyph_id);
+  if (check == -1) {
+    return -1;
+  }
+  IntegerList* glyph_array = GetGlyphArray();
+  IntegerList::iterator it = std::find(glyph_array->begin(),
+                                       glyph_array->end(),
+                                       glyph_id);
+  if (it == glyph_array->end()) {
+    return -1;
+  }
+  return (it - glyph_array->begin()) * ImageSize();
+}
+
+CALLER_ATTACH IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator*
+    IndexSubTableFormat5::Builder::GetIterator() {
+  Ptr<IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator> it =
+      new IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator(this);
+  return it.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat5::Builder*
+IndexSubTableFormat5::Builder::CreateBuilder() {
+  IndexSubTableFormat5BuilderPtr output = new IndexSubTableFormat5::Builder();
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat5::Builder*
+IndexSubTableFormat5::Builder::CreateBuilder(ReadableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  ReadableFontDataPtr new_data;
+  new_data.Attach(down_cast<ReadableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  if (new_data == NULL) {
+    return NULL;
+  }
+  IndexSubTableFormat5BuilderPtr output =
+      new IndexSubTableFormat5::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+// static
+CALLER_ATTACH IndexSubTableFormat5::Builder*
+IndexSubTableFormat5::Builder::CreateBuilder(WritableFontData* data,
+                                             int32_t index_sub_table_offset,
+                                             int32_t first_glyph_index,
+                                             int32_t last_glyph_index) {
+  int32_t length = Builder::DataLength(data,
+                                       index_sub_table_offset,
+                                       first_glyph_index,
+                                       last_glyph_index);
+  WritableFontDataPtr new_data;
+  new_data.Attach(down_cast<WritableFontData*>(
+      data->Slice(index_sub_table_offset, length)));
+  IndexSubTableFormat5BuilderPtr output =
+      new IndexSubTableFormat5::Builder(new_data,
+                                        first_glyph_index,
+                                        last_glyph_index);
+  return output.Detach();
+}
+
+CALLER_ATTACH FontDataTable* IndexSubTableFormat5::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  IndexSubTableFormat5Ptr output = new IndexSubTableFormat5(
+      data, first_glyph_index(), last_glyph_index());
+  return output.Detach();
+}
+
+void IndexSubTableFormat5::Builder::SubDataSet() {
+  Revert();
+}
+
+int32_t IndexSubTableFormat5::Builder::SubDataSizeToSerialize() {
+  if (glyph_array_.empty()) {
+    return InternalReadData()->Length();
+  }
+  return EblcTable::Offset::kIndexSubTable5_builderDataSize +
+         glyph_array_.size() * DataSize::kUSHORT;
+}
+
+bool IndexSubTableFormat5::Builder::SubReadyToSerialize() {
+  if (!glyph_array_.empty()) {
+    return true;
+  }
+  return false;
+}
+
+int32_t IndexSubTableFormat5::Builder::SubSerialize(
+    WritableFontData* new_data) {
+  int32_t size = SerializeIndexSubHeader(new_data);
+  if (!model_changed()) {
+    ReadableFontDataPtr source;
+    WritableFontDataPtr target;
+    source.Attach(down_cast<ReadableFontData*>(InternalReadData()->Slice(
+        EblcTable::Offset::kIndexSubTable5_imageSize)));
+    target.Attach(down_cast<WritableFontData*>(new_data->Slice(
+        EblcTable::Offset::kIndexSubTable5_imageSize)));
+    size += source->CopyTo(target);
+  } else {
+    size += new_data->WriteULong(EblcTable::Offset::kIndexSubTable5_imageSize,
+                                 ImageSize());
+    WritableFontDataPtr slice;
+    slice.Attach(down_cast<WritableFontData*>(new_data->Slice(size)));
+    size += BigMetrics()->SubSerialize(slice);
+    size += new_data->WriteULong(size, glyph_array_.size());
+    for (IntegerList::iterator b = glyph_array_.begin(), e = glyph_array_.end();
+                               b != e; b++) {
+      size += new_data->WriteUShort(size, *b);
+    }
+  }
+  return size;
+}
+
+int32_t IndexSubTableFormat5::Builder::ImageSize() {
+  return InternalReadData()->ReadULongAsInt(
+      EblcTable::Offset::kIndexSubTable5_imageSize);
+}
+
+void IndexSubTableFormat5::Builder::SetImageSize(int32_t image_size) {
+  InternalWriteData()->WriteULong(
+      EblcTable::Offset::kIndexSubTable5_imageSize, image_size);
+}
+
+BigGlyphMetrics::Builder* IndexSubTableFormat5::Builder::BigMetrics() {
+  if (metrics_ == NULL) {
+    WritableFontDataPtr data;
+    data.Attach(down_cast<WritableFontData*>(InternalWriteData()->Slice(
+        EblcTable::Offset::kIndexSubTable5_bigGlyphMetrics,
+        BigGlyphMetrics::Offset::kMetricsLength)));
+    metrics_ = new BigGlyphMetrics::Builder(data);
+    set_model_changed();
+  }
+  return metrics_;
+}
+
+IntegerList* IndexSubTableFormat5::Builder::GlyphArray() {
+  return GetGlyphArray();
+}
+
+void IndexSubTableFormat5::Builder::SetGlyphArray(const IntegerList& v) {
+  glyph_array_.clear();
+  glyph_array_ = v;
+  set_model_changed();
+}
+
+void IndexSubTableFormat5::Builder::Revert() {
+  glyph_array_.clear();
+  IndexSubTable::Builder::Revert();
+}
+
+IndexSubTableFormat5::Builder::Builder()
+    : IndexSubTable::Builder(EblcTable::Offset::kIndexSubTable5_builderDataSize,
+                             IndexSubTable::Format::FORMAT_5) {
+}
+
+IndexSubTableFormat5::Builder::Builder(WritableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IndexSubTableFormat5::Builder::Builder(ReadableFontData* data,
+                                       int32_t first_glyph_index,
+                                       int32_t last_glyph_index)
+    : IndexSubTable::Builder(data, first_glyph_index, last_glyph_index) {
+}
+
+IntegerList* IndexSubTableFormat5::Builder::GetGlyphArray() {
+  if (glyph_array_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &glyph_array_;
+}
+
+void IndexSubTableFormat5::Builder::Initialize(ReadableFontData* data) {
+  glyph_array_.clear();
+  if (data) {
+    int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data, 0);
+    for (int32_t i = 0; i < num_glyphs; ++i) {
+      glyph_array_.push_back(data->ReadUShort(
+          EblcTable::Offset::kIndexSubTable5_glyphArray +
+          i * DataSize::kUSHORT));
+    }
+  }
+}
+
+// static
+int32_t IndexSubTableFormat5::Builder::DataLength(
+    ReadableFontData* data,
+    int32_t index_sub_table_offset,
+    int32_t first_glyph_index,
+    int32_t last_glyph_index) {
+  int32_t num_glyphs = IndexSubTableFormat5::NumGlyphs(data,
+                                                       index_sub_table_offset);
+  UNREFERENCED_PARAMETER(first_glyph_index);
+  UNREFERENCED_PARAMETER(last_glyph_index);
+  return EblcTable::Offset::kIndexSubTable5_glyphArray +
+         num_glyphs * DataSize::kUSHORT;
+}
+
+/******************************************************************************
+ * IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator class
+ ******************************************************************************/
+IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::BitmapGlyphInfoIterator(
+    IndexSubTableFormat5::Builder* container)
+    : RefIterator<BitmapGlyphInfo, IndexSubTableFormat5::Builder,
+                  IndexSubTable::Builder>(container),
+      offset_index_(0) {
+}
+
+bool IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::HasNext() {
+  if (offset_index_ < (int32_t)(container()->GetGlyphArray()->size())) {
+    return true;
+  }
+  return false;
+}
+
+CALLER_ATTACH BitmapGlyphInfo*
+IndexSubTableFormat5::Builder::BitmapGlyphInfoIterator::Next() {
+  BitmapGlyphInfoPtr output;
+  if (!HasNext()) {
+    // Note: In C++, we do not throw exception when there's no element.
+    return NULL;
+  }
+  output = new BitmapGlyphInfo(container()->GetGlyphArray()->at(offset_index_),
+                               container()->image_data_offset(),
+                               offset_index_ * container()->ImageSize(),
+                               container()->ImageSize(),
+                               container()->image_format());
+  offset_index_++;
+  return output.Detach();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/index_sub_table_format5.h b/cpp/src/sfntly/table/bitmap/index_sub_table_format5.h
new file mode 100644
index 0000000..a39e88c
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/index_sub_table_format5.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_
+
+#include "sfntly/table/bitmap/big_glyph_metrics.h"
+#include "sfntly/table/bitmap/index_sub_table.h"
+
+namespace sfntly {
+
+class IndexSubTableFormat5 : public IndexSubTable,
+                             public RefCounted<IndexSubTableFormat5> {
+ public:
+  class Builder : public IndexSubTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    class BitmapGlyphInfoIterator
+        : public RefIterator<BitmapGlyphInfo, Builder, IndexSubTable::Builder> {
+     public:
+      explicit BitmapGlyphInfoIterator(Builder* container);
+      virtual ~BitmapGlyphInfoIterator() {}
+
+      virtual bool HasNext();
+      CALLER_ATTACH virtual BitmapGlyphInfo* Next();
+
+     private:
+      int32_t offset_index_;
+    };
+    virtual ~Builder();
+    virtual int32_t NumGlyphs();
+    virtual int32_t GlyphLength(int32_t glyph_id);
+    virtual int32_t GlyphStartOffset(int32_t glyph_id);
+    CALLER_ATTACH virtual BitmapGlyphInfoIterator* GetIterator();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+    int32_t ImageSize();
+    void SetImageSize(int32_t image_size);
+    BigGlyphMetrics::Builder* BigMetrics();
+    IntegerList* GlyphArray();
+    void SetGlyphArray(const IntegerList& v);
+
+    static CALLER_ATTACH Builder* CreateBuilder();
+    static CALLER_ATTACH Builder* CreateBuilder(ReadableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+    static CALLER_ATTACH Builder* CreateBuilder(WritableFontData* data,
+                                                int32_t index_sub_table_offset,
+                                                int32_t first_glyph_index,
+                                                int32_t last_glyph_index);
+   protected:
+    void Revert();
+
+   private:
+    Builder();
+    Builder(WritableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+    Builder(ReadableFontData* data,
+            int32_t first_glyph_index,
+            int32_t last_glyph_index);
+
+    IntegerList* GetGlyphArray();
+    void Initialize(ReadableFontData* data);
+
+    static int32_t DataLength(ReadableFontData* data,
+                              int32_t index_sub_table_offset,
+                              int32_t first_glyph_index,
+                              int32_t last_glyph_index);
+
+    IntegerList glyph_array_;
+    BigGlyphMetricsBuilderPtr metrics_;
+  };
+  virtual ~IndexSubTableFormat5();
+
+  virtual int32_t NumGlyphs();
+  virtual int32_t GlyphStartOffset(int32_t glyph_id);
+  virtual int32_t GlyphLength(int32_t glyph_id);
+
+  int32_t ImageSize();
+  CALLER_ATTACH BigGlyphMetrics* BigMetrics();
+
+ private:
+  IndexSubTableFormat5(ReadableFontData* data,
+                       int32_t first_glyph_index,
+                       int32_t last_glyph_index);
+
+  static int32_t NumGlyphs(ReadableFontData* dta, int32_t table_offset);
+
+  int32_t image_size_;
+
+  friend class Builder;
+};
+typedef Ptr<IndexSubTableFormat5> IndexSubTableFormat5Ptr;
+typedef Ptr<IndexSubTableFormat5::Builder> IndexSubTableFormat5BuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_INDEX_SUBTABLE_FORMAT5_H_
diff --git a/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.cc b/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.cc
new file mode 100644
index 0000000..87031a1
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0  = the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/simple_bitmap_glyph.h"
+
+namespace sfntly {
+
+SimpleBitmapGlyph::SimpleBitmapGlyph(ReadableFontData* data, int32_t format)
+    : BitmapGlyph(data, format) {
+}
+
+SimpleBitmapGlyph::~SimpleBitmapGlyph() {
+}
+
+SimpleBitmapGlyph::Builder::Builder(ReadableFontData* data, int32_t format)
+    : BitmapGlyph::Builder(data, format) {
+}
+
+SimpleBitmapGlyph::Builder::Builder(WritableFontData* data, int32_t format)
+    : BitmapGlyph::Builder(data, format) {
+}
+
+SimpleBitmapGlyph::Builder::~Builder() {
+}
+
+CALLER_ATTACH FontDataTable*
+SimpleBitmapGlyph::Builder::SubBuildTable(ReadableFontData* data) {
+  Ptr<SimpleBitmapGlyph> glyph = new SimpleBitmapGlyph(data, format());
+  return glyph.Detach();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.h b/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.h
new file mode 100644
index 0000000..56ede10
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/simple_bitmap_glyph.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0  = the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_
+
+#include "sfntly/table/bitmap/bitmap_glyph.h"
+
+namespace sfntly {
+
+class SimpleBitmapGlyph : public BitmapGlyph,
+                          public RefCounted<SimpleBitmapGlyph> {
+ public:
+  class Builder : public BitmapGlyph::Builder,
+                  public RefCounted<Builder> {
+   public:
+    Builder(WritableFontData* data, int32_t format);
+    Builder(ReadableFontData* data, int32_t format);
+    virtual ~Builder();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+  };
+
+  SimpleBitmapGlyph(ReadableFontData* data, int32_t format);
+  virtual ~SimpleBitmapGlyph();
+};
+typedef Ptr<SimpleBitmapGlyph> SimpleBitmapGlyphPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SIMPLE_BITMAP_GLYPH_H_
diff --git a/cpp/src/sfntly/table/bitmap/small_glyph_metrics.cc b/cpp/src/sfntly/table/bitmap/small_glyph_metrics.cc
new file mode 100644
index 0000000..0f3c1e9
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/small_glyph_metrics.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/bitmap/small_glyph_metrics.h"
+
+namespace sfntly {
+/******************************************************************************
+ * SmallGlyphMetrics class
+ ******************************************************************************/
+SmallGlyphMetrics::SmallGlyphMetrics(ReadableFontData* data)
+    : GlyphMetrics(data) {
+}
+
+SmallGlyphMetrics::~SmallGlyphMetrics() {
+}
+
+int32_t SmallGlyphMetrics::Height() {
+  return data_->ReadByte(Offset::kHeight);
+}
+
+int32_t SmallGlyphMetrics::Width() {
+  return data_->ReadByte(Offset::kWidth);
+}
+
+int32_t SmallGlyphMetrics::BearingX() {
+  return data_->ReadByte(Offset::kBearingX);
+}
+
+int32_t SmallGlyphMetrics::BearingY() {
+  return data_->ReadByte(Offset::kBearingY);
+}
+
+int32_t SmallGlyphMetrics::Advance() {
+  return data_->ReadByte(Offset::kAdvance);
+}
+
+/******************************************************************************
+ * SmallGlyphMetrics::Builder class
+ ******************************************************************************/
+SmallGlyphMetrics::Builder::Builder(WritableFontData* data)
+    : GlyphMetrics::Builder(data) {
+}
+
+SmallGlyphMetrics::Builder::Builder(ReadableFontData* data)
+    : GlyphMetrics::Builder(data) {
+}
+
+SmallGlyphMetrics::Builder::~Builder() {
+}
+
+int32_t SmallGlyphMetrics::Builder::Height() {
+  return InternalReadData()->ReadByte(Offset::kHeight);
+}
+
+void SmallGlyphMetrics::Builder::SetHeight(byte_t height) {
+  InternalWriteData()->WriteByte(Offset::kHeight, height);
+}
+
+int32_t SmallGlyphMetrics::Builder::Width() {
+  return InternalReadData()->ReadByte(Offset::kWidth);
+}
+
+void SmallGlyphMetrics::Builder::SetWidth(byte_t width) {
+  InternalWriteData()->WriteByte(Offset::kWidth, width);
+}
+
+int32_t SmallGlyphMetrics::Builder::BearingX() {
+  return InternalReadData()->ReadByte(Offset::kBearingX);
+}
+
+void SmallGlyphMetrics::Builder::SetBearingX(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kBearingX, bearing);
+}
+
+int32_t SmallGlyphMetrics::Builder::BearingY() {
+  return InternalReadData()->ReadByte(Offset::kBearingY);
+}
+
+void SmallGlyphMetrics::Builder::SetBearingY(byte_t bearing) {
+  InternalWriteData()->WriteByte(Offset::kBearingY, bearing);
+}
+
+int32_t SmallGlyphMetrics::Builder::Advance() {
+  return InternalReadData()->ReadByte(Offset::kAdvance);
+}
+
+void SmallGlyphMetrics::Builder::SetAdvance(byte_t advance) {
+  InternalWriteData()->WriteByte(Offset::kAdvance, advance);
+}
+
+CALLER_ATTACH FontDataTable*
+    SmallGlyphMetrics::Builder::SubBuildTable(ReadableFontData* data) {
+  SmallGlyphMetricsPtr output = new SmallGlyphMetrics(data);
+  return output.Detach();
+}
+
+void SmallGlyphMetrics::Builder::SubDataSet() {
+  // NOP.
+}
+
+int32_t SmallGlyphMetrics::Builder::SubDataSizeToSerialize() {
+  return 0;
+}
+
+bool SmallGlyphMetrics::Builder::SubReadyToSerialize() {
+  return false;
+}
+
+int32_t SmallGlyphMetrics::Builder::SubSerialize(WritableFontData* new_data) {
+  return Data()->CopyTo(new_data);
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/bitmap/small_glyph_metrics.h b/cpp/src/sfntly/table/bitmap/small_glyph_metrics.h
new file mode 100644
index 0000000..ea13720
--- /dev/null
+++ b/cpp/src/sfntly/table/bitmap/small_glyph_metrics.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/table/bitmap/glyph_metrics.h"
+
+namespace sfntly {
+
+class SmallGlyphMetrics : public GlyphMetrics,
+                          public RefCounted<SmallGlyphMetrics> {
+ public:
+  struct Offset {
+    enum {
+      kMetricsLength = 5,
+      kHeight = 0,
+      kWidth = 1,
+      kBearingX = 2,
+      kBearingY = 3,
+      kAdvance = 4,
+    };
+  };
+
+  class Builder : public GlyphMetrics::Builder,
+                  public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    explicit Builder(WritableFontData* data);
+    explicit Builder(ReadableFontData* data);
+    virtual ~Builder();
+
+    int32_t Height();
+    void SetHeight(byte_t height);
+    int32_t Width();
+    void SetWidth(byte_t width);
+    int32_t BearingX();
+    void SetBearingX(byte_t bearing);
+    int32_t BearingY();
+    void SetBearingY(byte_t bearing);
+    int32_t Advance();
+    void SetAdvance(byte_t advance);
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+  };
+
+  explicit SmallGlyphMetrics(ReadableFontData* data);
+  virtual ~SmallGlyphMetrics();
+
+  int32_t Height();
+  int32_t Width();
+  int32_t BearingX();
+  int32_t BearingY();
+  int32_t Advance();
+};
+typedef Ptr<SmallGlyphMetrics> SmallGlyphMetricsPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BITMAP_SMALL_GLYPH_METRICS_H_
diff --git a/cpp/src/sfntly/table/byte_array_table_builder.cc b/cpp/src/sfntly/table/byte_array_table_builder.cc
new file mode 100644
index 0000000..631a05f
--- /dev/null
+++ b/cpp/src/sfntly/table/byte_array_table_builder.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/byte_array_table_builder.h"
+
+namespace sfntly {
+
+ByteArrayTableBuilder::~ByteArrayTableBuilder() {}
+
+int32_t ByteArrayTableBuilder::ByteValue(int32_t index) {
+  ReadableFontDataPtr data = InternalReadData();
+  if (data == NULL) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("No font data for the table");
+#endif
+    return -1;
+  }
+  return data->ReadByte(index);
+}
+
+void ByteArrayTableBuilder::SetByteValue(int32_t index, byte_t b) {
+  WritableFontDataPtr data = InternalWriteData();
+  if (data == NULL) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("No font data for the table");
+#endif
+    return;
+  }
+  data->WriteByte(index, b);
+}
+
+int32_t ByteArrayTableBuilder::ByteCount() {
+  ReadableFontDataPtr data = InternalReadData();
+  if (data == NULL) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IOException("No font data for the table");
+#endif
+    return 0;
+  }
+  return data->Length();
+}
+
+ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header,
+                                               WritableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header,
+                                               ReadableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+ByteArrayTableBuilder::ByteArrayTableBuilder(Header* header)
+    : TableBasedTableBuilder(header) {
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/byte_array_table_builder.h b/cpp/src/sfntly/table/byte_array_table_builder.h
new file mode 100644
index 0000000..42d27a8
--- /dev/null
+++ b/cpp/src/sfntly/table/byte_array_table_builder.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_
+
+#include "sfntly/table/table_based_table_builder.h"
+
+namespace sfntly {
+
+// An abstract builder base for byte array based tables.
+class ByteArrayTableBuilder : public TableBasedTableBuilder {
+ public:
+  virtual ~ByteArrayTableBuilder();
+
+  // Get the byte value at the specified index. The index is relative to the
+  // start of the table.
+  // @param index index relative to the start of the table
+  // @return byte value at the given index
+  virtual int32_t ByteValue(int32_t index);
+
+  // Set the byte value at the specified index. The index is relative to the
+  // start of the table.
+  // @param index index relative to the start of the table
+  // @param b byte value to set
+  virtual void SetByteValue(int32_t index, byte_t b);
+
+  // Get the number of bytes set for this table. It may include padding bytes at
+  // the end.
+  virtual int32_t ByteCount();
+
+ protected:
+  ByteArrayTableBuilder(Header* header, WritableFontData* data);
+  ByteArrayTableBuilder(Header* header, ReadableFontData* data);
+  explicit ByteArrayTableBuilder(Header* header);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_
diff --git a/cpp/src/sfntly/table/core/cmap_table.cc b/cpp/src/sfntly/table/core/cmap_table.cc
new file mode 100644
index 0000000..1c83d2e
--- /dev/null
+++ b/cpp/src/sfntly/table/core/cmap_table.cc
@@ -0,0 +1,1287 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// type.h needs to be included first because of building issues on Windows
+// Type aliases we delcare are defined in other headers and make the build
+// fail otherwise.
+#include "sfntly/port/type.h"
+#include "sfntly/table/core/cmap_table.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <utility>
+
+#include "sfntly/font.h"
+#include "sfntly/math/font_math.h"
+#include "sfntly/port/endian.h"
+#include "sfntly/port/exception_type.h"
+#include "sfntly/table/core/name_table.h"
+
+namespace sfntly {
+
+const int32_t CMapTable::NOTDEF = 0;
+
+CMapTable::CMapId CMapTable::WINDOWS_BMP = {
+  PlatformId::kWindows,
+  WindowsEncodingId::kUnicodeUCS2
+};
+CMapTable::CMapId CMapTable::WINDOWS_UCS4 = {
+  PlatformId::kWindows,
+  WindowsEncodingId::kUnicodeUCS4
+};
+CMapTable::CMapId CMapTable::MAC_ROMAN = {
+  PlatformId::kWindows,
+  MacintoshEncodingId::kRoman
+};
+
+/******************************************************************************
+ * CMapTable class
+ ******************************************************************************/
+CMapTable::CMapTable(Header* header, ReadableFontData* data)
+  : SubTableContainerTable(header, data) {
+}
+
+CMapTable::~CMapTable() {}
+
+CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t index) {
+  if (index < 0 || index > NumCMaps()) {
+#ifndef SFNTLY_NO_EXCEPTION
+    throw IndexOutOfBoundException("Requested CMap index is out of bounds.");
+#else
+    return NULL;
+#endif
+  }
+  int32_t platform_id = PlatformId(index);
+  int32_t encoding_id = EncodingId(index);
+  CMapId cmap_id = NewCMapId(platform_id, encoding_id);
+  int32_t offset_ = Offset(index);
+  Ptr<FontDataTable::Builder> cmap_builder =
+      (CMap::Builder::GetBuilder(data_, offset_, cmap_id));
+  if (!cmap_builder) {
+#ifndef SFNTLY_NO_EXCEPTION
+    throw NoSuchElementException("Cannot find builder for requested CMap.");
+#else
+    return NULL;
+#endif
+  }
+  return down_cast<CMapTable::CMap*>(cmap_builder->Build());
+}
+
+CALLER_ATTACH CMapTable::CMap* CMapTable::GetCMap(const int32_t platform_id,
+                                                  const int32_t encoding_id) {
+  return GetCMap(NewCMapId(platform_id, encoding_id));
+}
+
+CALLER_ATTACH CMapTable::CMap*
+CMapTable::GetCMap(const CMapTable::CMapId cmap_id) {
+  CMapIdFilter id_filter(cmap_id);
+  CMapIterator cmap_iterator(this, &id_filter);
+  // There can only be one cmap with a particular CMapId
+  if (cmap_iterator.HasNext()) {
+    Ptr<CMapTable::CMap> cmap;
+    cmap.Attach(cmap_iterator.Next());
+    return cmap.Detach();
+  }
+#ifndef SFNTLY_NO_EXCEPTION
+  throw NoSuchElementException();
+#else
+  return NULL;
+#endif
+}
+
+int32_t CMapTable::Version() {
+  return data_->ReadUShort(Offset::kVersion);
+}
+
+int32_t CMapTable::NumCMaps() {
+  return data_->ReadUShort(Offset::kNumTables);
+}
+
+CMapTable::CMapId CMapTable::GetCMapId(int32_t index) {
+  return NewCMapId(PlatformId(index), EncodingId(index));
+}
+
+int32_t CMapTable::PlatformId(int32_t index) {
+  return data_->ReadUShort(Offset::kEncodingRecordPlatformId +
+                           OffsetForEncodingRecord(index));
+}
+
+int32_t CMapTable::EncodingId(int32_t index) {
+  return data_->ReadUShort(Offset::kEncodingRecordEncodingId +
+                           OffsetForEncodingRecord(index));
+}
+
+int32_t CMapTable::Offset(int32_t index) {
+  return data_->ReadULongAsInt(Offset::kEncodingRecordOffset +
+                               OffsetForEncodingRecord(index));
+}
+
+int32_t CMapTable::OffsetForEncodingRecord(int32_t index) {
+  return Offset::kEncodingRecordStart + index * Offset::kEncodingRecordSize;
+}
+
+CMapTable::CMapId CMapTable::NewCMapId(int32_t platform_id,
+                                       int32_t encoding_id) {
+  CMapId result;
+  result.platform_id = platform_id;
+  result.encoding_id = encoding_id;
+  return result;
+}
+
+CMapTable::CMapId CMapTable::NewCMapId(const CMapId& obj) {
+  CMapId result;
+  result.platform_id = obj.platform_id;
+  result.encoding_id = obj.encoding_id;
+  return result;
+}
+
+/******************************************************************************
+ * CMapTable::CMapIterator class
+ ******************************************************************************/
+CMapTable::CMapIterator::CMapIterator(CMapTable* table,
+                                      const CMapFilter* filter)
+    : table_index_(0), filter_(filter), table_(table) {
+}
+
+bool CMapTable::CMapIterator::HasNext() {
+  if (!filter_) {
+    if (table_index_ < table_->NumCMaps()) {
+      return true;
+    }
+    return false;
+  }
+
+  for (; table_index_ < table_->NumCMaps(); ++table_index_) {
+    if (filter_->accept(table_->GetCMapId(table_index_))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+CALLER_ATTACH CMapTable::CMap* CMapTable::CMapIterator::Next() {
+  if (!HasNext()) {
+#ifndef SFNTLY_NO_EXCEPTION
+    throw NoSuchElementException();
+#else
+    return NULL;
+#endif
+  }
+  CMapPtr next_cmap;
+  next_cmap.Attach(table_->GetCMap(table_index_++));
+  if (next_cmap == NULL) {
+#ifndef SFNTLY_NO_EXCEPTION
+    throw NoSuchElementException("Error during the creation of the CMap");
+#else
+    return NULL;
+#endif
+  }
+  return next_cmap.Detach();
+}
+
+/******************************************************************************
+ * CMapTable::CMapId class
+ ******************************************************************************/
+
+/******************************************************************************
+ * CMapTable::CMapIdComparator class
+ ******************************************************************************/
+
+bool CMapTable::CMapIdComparator::operator()(const CMapId& lhs,
+                                             const CMapId& rhs) const {
+  return ((lhs.platform_id << 8 | lhs.encoding_id) >
+      (rhs.platform_id << 8 | rhs.encoding_id));
+}
+
+/******************************************************************************
+ * CMapTable::CMapIdFilter class
+ ******************************************************************************/
+CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id)
+    : wanted_id_(wanted_id),
+      comparator_(NULL) {
+}
+
+CMapTable::CMapIdFilter::CMapIdFilter(const CMapId wanted_id,
+                                      const CMapIdComparator* comparator)
+    : wanted_id_(wanted_id),
+      comparator_(comparator) {
+}
+
+bool CMapTable::CMapIdFilter::accept(const CMapId& cmap_id) const {
+  if (!comparator_)
+    return wanted_id_ == cmap_id;
+  return (*comparator_)(wanted_id_, cmap_id);
+}
+
+/******************************************************************************
+ * CMapTable::CMap class
+ ******************************************************************************/
+CMapTable::CMap::CMap(ReadableFontData* data, int32_t format,
+                      const CMapId& cmap_id)
+    : SubTable(data), format_(format), cmap_id_(cmap_id) {
+}
+
+CMapTable::CMap::~CMap() {
+}
+
+/******************************************************************************
+ * CMapTable::CMap::Builder class
+ ******************************************************************************/
+CMapTable::CMap::Builder::~Builder() {
+}
+
+CALLER_ATTACH CMapTable::CMap::Builder*
+    CMapTable::CMap::Builder::GetBuilder(ReadableFontData* data, int32_t offset,
+                                         const CMapId& cmap_id) {
+  // NOT IMPLEMENTED: Java enum value validation
+  int32_t format = data->ReadUShort(offset);
+  CMapBuilderPtr builder;
+  switch (format) {
+    case CMapFormat::kFormat0:
+      builder.Attach(CMapFormat0::Builder::NewInstance(data, offset, cmap_id));
+      break;
+    case CMapFormat::kFormat2:
+#if defined (SFNTLY_DEBUG_CMAP)
+      fprintf(stderr, "Requesting Format2 builder, but it's unsupported; "
+              "returning NULL\n");
+#endif
+      break;
+    case CMapFormat::kFormat4:
+      builder.Attach(CMapFormat4::Builder::NewInstance(data, offset, cmap_id));
+      break;
+    default:
+#ifdef SFNTLY_DEBUG_CMAP
+      fprintf(stderr, "Unknown builder format requested\n");
+#endif
+      break;
+  }
+  return builder.Detach();
+}
+
+CALLER_ATTACH CMapTable::CMap::Builder*
+CMapTable::CMap::Builder::GetBuilder(int32_t format, const CMapId& cmap_id) {
+  Ptr<CMapTable::CMap::Builder> builder;
+  switch (format) {
+    case CMapFormat::kFormat0:
+      builder.Attach(CMapFormat0::Builder::NewInstance(cmap_id));
+      break;
+    case CMapFormat::kFormat2:
+#if defined (SFNTLY_DEBUG_CMAP)
+      fprintf(stderr, "Requesting Format2 builder, but it's unsupported; "
+              "returning NULL\n");
+#endif
+      break;
+    case CMapFormat::kFormat4:
+      builder.Attach(CMapFormat4::Builder::NewInstance(cmap_id));
+      break;
+    default:
+#ifdef SFNTLY_DEBUG_CMAP
+      fprintf(stderr, "Unknown builder format requested\n");
+#endif
+      break;
+  }
+  return builder.Detach();
+}
+
+CMapTable::CMap::Builder::Builder(ReadableFontData* data,
+                                  int32_t format,
+                                  const CMapId& cmap_id)
+    : SubTable::Builder(data),
+      format_(format),
+      cmap_id_(cmap_id),
+      language_(0) {
+}
+
+CMapTable::CMap::Builder::Builder(WritableFontData* data,
+                                  int32_t format,
+                                  const CMapId& cmap_id)
+    : SubTable::Builder(data),
+      format_(format),
+      cmap_id_(cmap_id),
+      language_(0) {
+}
+
+int32_t CMapTable::CMap::Builder::SubSerialize(WritableFontData* new_data) {
+  return InternalReadData()->CopyTo(new_data);
+}
+
+bool CMapTable::CMap::Builder::SubReadyToSerialize() {
+  return true;
+}
+
+int32_t CMapTable::CMap::Builder::SubDataSizeToSerialize() {
+  ReadableFontDataPtr read_data = InternalReadData();
+  if (!read_data)
+    return 0;
+  return read_data->Length();
+}
+
+void CMapTable::CMap::Builder::SubDataSet() {
+  // NOP
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat0
+ ******************************************************************************/
+CMapTable::CMapFormat0::~CMapFormat0() {
+}
+
+int32_t CMapTable::CMapFormat0::Language() {
+  return 0;
+}
+
+int32_t CMapTable::CMapFormat0::GlyphId(int32_t character) {
+  if (character < 0 || character > 255) {
+    return CMapTable::NOTDEF;
+  }
+  return data_->ReadUByte(character + Offset::kFormat0GlyphIdArray);
+}
+
+CMapTable::CMapFormat0::CMapFormat0(ReadableFontData* data,
+                                    const CMapId& cmap_id)
+    : CMap(data, CMapFormat::kFormat0, cmap_id) {
+}
+
+CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat0::Iterator() {
+  return new CMapTable::CMapFormat0::CharacterIterator(0, 0xff);
+}
+
+
+/******************************************************************************
+ * CMapTable::CMapFormat0::CharacterIterator
+ ******************************************************************************/
+CMapTable::CMapFormat0::CharacterIterator::CharacterIterator(int32_t start,
+                                                             int32_t end)
+    : character_(start),
+    max_character_(end) {
+}
+
+CMapTable::CMapFormat0::CharacterIterator::~CharacterIterator() {}
+
+bool CMapTable::CMapFormat0::CharacterIterator::HasNext() {
+  return character_ < max_character_;
+}
+
+int32_t CMapTable::CMapFormat0::CharacterIterator::Next() {
+  if (HasNext())
+    return character_++;
+#ifndef SFNTLY_NO_EXCEPTION
+  throw NoSuchElementException("No more characters to iterate.");
+#endif
+  return -1;
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat0::Builder
+ ******************************************************************************/
+// static
+CALLER_ATTACH CMapTable::CMapFormat0::Builder*
+CMapTable::CMapFormat0::Builder::NewInstance(WritableFontData* data,
+                                             int32_t offset,
+                                             const CMapId& cmap_id) {
+  WritableFontDataPtr wdata;
+  if (data) {
+    wdata.Attach(down_cast<WritableFontData*>(
+        data->Slice(offset,
+                    data->ReadUShort(offset + Offset::kFormat0Length))));
+  }
+  return new Builder(wdata, CMapFormat::kFormat0, cmap_id);
+}
+
+// static
+CALLER_ATTACH CMapTable::CMapFormat0::Builder*
+CMapTable::CMapFormat0::Builder::NewInstance(ReadableFontData* data,
+                                             int32_t offset,
+                                             const CMapId& cmap_id) {
+  ReadableFontDataPtr rdata;
+  if (data) {
+    rdata.Attach(down_cast<ReadableFontData*>(
+        data->Slice(offset,
+                    data->ReadUShort(offset + Offset::kFormat0Length))));
+  }
+  return new Builder(rdata, CMapFormat::kFormat0, cmap_id);
+}
+
+// static
+CALLER_ATTACH CMapTable::CMapFormat0::Builder*
+CMapTable::CMapFormat0::Builder::NewInstance(const CMapId& cmap_id) {
+  return new Builder(cmap_id);
+}
+
+// Always call NewInstance instead of the constructor for creating a new builder
+// object! This refactoring avoids memory leaks when slicing the font data.
+CMapTable::CMapFormat0::Builder::Builder(WritableFontData* data, int32_t offset,
+                                         const CMapId& cmap_id)
+    : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) {
+  UNREFERENCED_PARAMETER(offset);
+}
+
+CMapTable::CMapFormat0::Builder::Builder(
+    ReadableFontData* data,
+    int32_t offset,
+    const CMapId& cmap_id)
+    : CMapTable::CMap::Builder(data, CMapFormat::kFormat0, cmap_id) {
+  UNREFERENCED_PARAMETER(offset);
+}
+
+CMapTable::CMapFormat0::Builder::Builder(const CMapId& cmap_id)
+    : CMap::Builder(reinterpret_cast<ReadableFontData*>(NULL),
+                    CMapFormat::kFormat0,
+                    cmap_id) {
+}
+
+CMapTable::CMapFormat0::Builder::~Builder() {
+}
+
+CALLER_ATTACH FontDataTable*
+    CMapTable::CMapFormat0::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new CMapFormat0(data, cmap_id());
+  return table.Detach();
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat2
+ ******************************************************************************/
+CMapTable::CMapFormat2::~CMapFormat2() {
+}
+
+int32_t CMapTable::CMapFormat2::Language() {
+  return 0;
+}
+
+int32_t CMapTable::CMapFormat2::GlyphId(int32_t character) {
+  if (character > 0xffff) {
+    return CMapTable::NOTDEF;
+  }
+
+  uint32_t c = ToBE32(character);
+  byte_t high_byte = (c >> 8) & 0xff;
+  byte_t low_byte = c & 0xff;
+  int32_t offset = SubHeaderOffset(high_byte);
+
+  if (offset == 0) {
+    low_byte = high_byte;
+    high_byte = 0;
+  }
+
+  int32_t first_code = FirstCode(high_byte);
+  int32_t entry_count = EntryCount(high_byte);
+
+  if (low_byte < first_code || low_byte >= first_code + entry_count) {
+    return CMapTable::NOTDEF;
+  }
+
+  int32_t id_range_offset = IdRangeOffset(high_byte);
+
+  // position of idRangeOffset + value of idRangeOffset + index for low byte
+  // = firstcode
+  int32_t p_location = (offset + Offset::kFormat2SubHeader_idRangeOffset) +
+      id_range_offset +
+      (low_byte - first_code) * DataSize::kUSHORT;
+  int p = data_->ReadUShort(p_location);
+  if (p == 0) {
+    return CMapTable::NOTDEF;
+  }
+
+  if (offset == 0) {
+    return p;
+  }
+  int id_delta = IdDelta(high_byte);
+  return (p + id_delta) % 65536;
+}
+
+int32_t CMapTable::CMapFormat2::BytesConsumed(int32_t character) {
+  uint32_t c = ToBE32(character);
+  int32_t high_byte = (c >> 8) & 0xff;
+  int32_t offset = SubHeaderOffset(high_byte);
+  return (offset == 0) ? 1 : 2;
+}
+
+CMapTable::CMapFormat2::CMapFormat2(ReadableFontData* data,
+                                    const CMapId& cmap_id)
+    : CMap(data, CMapFormat::kFormat2, cmap_id) {
+}
+
+int32_t CMapTable::CMapFormat2::SubHeaderOffset(int32_t sub_header_index) {
+  return data_->ReadUShort(Offset::kFormat2SubHeaderKeys +
+                           sub_header_index * DataSize::kUSHORT);
+}
+
+int32_t CMapTable::CMapFormat2::FirstCode(int32_t sub_header_index) {
+  int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
+  return data_->ReadUShort(sub_header_offset +
+                           Offset::kFormat2SubHeaderKeys +
+                           Offset::kFormat2SubHeader_firstCode);
+}
+
+int32_t CMapTable::CMapFormat2::EntryCount(int32_t sub_header_index) {
+  int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
+  return data_->ReadUShort(sub_header_offset +
+                           Offset::kFormat2SubHeaderKeys +
+                           Offset::kFormat2SubHeader_entryCount);
+}
+
+int32_t CMapTable::CMapFormat2::IdRangeOffset(int32_t sub_header_index) {
+  int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
+  return data_->ReadUShort(sub_header_offset +
+                           Offset::kFormat2SubHeaderKeys +
+                           Offset::kFormat2SubHeader_idRangeOffset);
+}
+
+int32_t CMapTable::CMapFormat2::IdDelta(int32_t sub_header_index) {
+  int32_t sub_header_offset = SubHeaderOffset(sub_header_index);
+  return data_->ReadUShort(sub_header_offset +
+                           Offset::kFormat2SubHeaderKeys +
+                           Offset::kFormat2SubHeader_idDelta);
+}
+
+CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat2::Iterator() {
+  // UNIMPLEMENTED
+  return NULL;
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat2::Builder
+ ******************************************************************************/
+CMapTable::CMapFormat2::Builder::Builder(WritableFontData* data,
+                                         int32_t offset,
+                                         const CMapId& cmap_id)
+    : CMapTable::CMap::Builder(data ? down_cast<WritableFontData*>(
+                                   data->Slice(offset, data->ReadUShort(
+                                       offset + Offset::kFormat0Length)))
+                               : reinterpret_cast<WritableFontData*>(NULL),
+                               CMapFormat::kFormat2, cmap_id) {
+  // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix.
+}
+
+CMapTable::CMapFormat2::Builder::Builder(ReadableFontData* data,
+                                         int32_t offset,
+                                         const CMapId& cmap_id)
+    : CMapTable::CMap::Builder(data ? down_cast<ReadableFontData*>(
+                                   data->Slice(offset, data->ReadUShort(
+                                       offset + Offset::kFormat0Length)))
+                               : reinterpret_cast<ReadableFontData*>(NULL),
+                               CMapFormat::kFormat2, cmap_id) {
+  // TODO(arthurhsu): FIXIT: heavy lifting and leak, need fix.
+}
+
+CMapTable::CMapFormat2::Builder::~Builder() {
+}
+
+CALLER_ATTACH FontDataTable*
+    CMapTable::CMapFormat2::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new CMapFormat2(data, cmap_id());
+  return table.Detach();
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat4
+ ******************************************************************************/
+CMapTable::CMapFormat4::CMapFormat4(ReadableFontData* data,
+                                    const CMapId& cmap_id)
+    : CMap(data, CMapFormat::kFormat4, cmap_id),
+      seg_count_(SegCount(data)),
+      start_code_offset_(StartCodeOffset(seg_count_)),
+      id_delta_offset_(IdDeltaOffset(seg_count_)),
+      glyph_id_array_offset_(GlyphIdArrayOffset(seg_count_)) {
+}
+
+CMapTable::CMapFormat4::~CMapFormat4() {
+}
+
+int32_t CMapTable::CMapFormat4::GlyphId(int32_t character) {
+  int32_t segment = data_->SearchUShort(StartCodeOffset(seg_count_),
+                                        DataSize::kUSHORT,
+                                        Offset::kFormat4EndCount,
+                                        DataSize::kUSHORT,
+                                        seg_count_,
+                                        character);
+  if (segment == -1) {
+    return CMapTable::NOTDEF;
+  }
+  int32_t start_code = StartCode(segment);
+  return RetrieveGlyphId(segment, start_code, character);
+}
+
+int32_t CMapTable::CMapFormat4::RetrieveGlyphId(int32_t segment,
+                                                int32_t start_code,
+                                                int32_t character) {
+  if (character < start_code) {
+    return CMapTable::NOTDEF;
+  }
+  int32_t id_range_offset = IdRangeOffset(segment);
+  if (id_range_offset == 0) {
+    return (character + IdDelta(segment)) % 65536;
+  }
+  return data_->ReadUShort(id_range_offset +
+                           IdRangeOffsetLocation(segment) +
+                           2 * (character - start_code));
+}
+
+int32_t CMapTable::CMapFormat4::seg_count() {
+  return seg_count_;
+}
+
+int32_t CMapTable::CMapFormat4::Length() {
+  return Length(data_);
+}
+
+int32_t CMapTable::CMapFormat4::StartCode(int32_t segment) {
+  if (!IsValidIndex(segment)) {
+    return -1;
+  }
+  return StartCode(data_.p_, seg_count_, segment);
+}
+
+// static
+int32_t CMapTable::CMapFormat4::Language(ReadableFontData* data) {
+  int32_t language = data->ReadUShort(Offset::kFormat4Language);
+  return language;
+}
+
+// static
+int32_t CMapTable::CMapFormat4::Length(ReadableFontData* data) {
+  int32_t length = data->ReadUShort(Offset::kFormat4Length);
+  return length;
+}
+
+// static
+int32_t CMapTable::CMapFormat4::SegCount(ReadableFontData* data) {
+  int32_t seg_count = data->ReadUShort(Offset::kFormat4SegCountX2) / 2;
+  return seg_count;
+}
+
+// static
+int32_t CMapTable::CMapFormat4::StartCode(ReadableFontData* data,
+                                          int32_t seg_count,
+                                          int32_t index) {
+  int32_t start_code = data->ReadUShort(StartCodeOffset(seg_count) +
+                                        index * DataSize::kUSHORT);
+  return start_code;
+}
+
+// static
+int32_t CMapTable::CMapFormat4::StartCodeOffset(int32_t seg_count) {
+  int32_t start_code_offset = Offset::kFormat4EndCount +
+      (seg_count + 1) * DataSize::kUSHORT;
+  return start_code_offset;
+}
+
+// static
+int32_t CMapTable::CMapFormat4::EndCode(ReadableFontData* data,
+                                        int32_t seg_count,
+                                        int32_t index) {
+  UNREFERENCED_PARAMETER(seg_count);
+  int32_t end_code = data->ReadUShort(Offset::kFormat4EndCount +
+                                      index * DataSize::kUSHORT);
+  return end_code;
+}
+
+// static
+int32_t CMapTable::CMapFormat4::IdDelta(ReadableFontData* data,
+                                        int32_t seg_count,
+                                        int32_t index) {
+  int32_t id_delta = data->ReadUShort(IdDeltaOffset(seg_count) +
+                                      index * DataSize::kUSHORT);
+  return id_delta;
+}
+
+// static
+int32_t CMapTable::CMapFormat4::IdDeltaOffset(int32_t seg_count) {
+  int32_t id_delta_offset =
+      Offset::kFormat4EndCount + (2 * seg_count + 1) * DataSize::kUSHORT;
+  return id_delta_offset;
+}
+
+// static
+int32_t CMapTable::CMapFormat4::IdRangeOffset(ReadableFontData* data,
+                                              int32_t seg_count,
+                                              int32_t index) {
+  int32_t id_range_offset =
+      data->ReadUShort(IdRangeOffsetOffset(seg_count)
+                       + index * DataSize::kUSHORT);
+  return id_range_offset;
+}
+
+// static
+int32_t CMapTable::CMapFormat4::IdRangeOffsetOffset(int32_t seg_count) {
+  int32_t id_range_offset_offset =
+      Offset::kFormat4EndCount + (2 * seg_count + 1) * DataSize::kUSHORT +
+      seg_count * DataSize::kSHORT;
+  return id_range_offset_offset;
+}
+
+// static
+int32_t CMapTable::CMapFormat4::GlyphIdArrayOffset(int32_t seg_count) {
+  int32_t glyph_id_array_offset =
+      Offset::kFormat4EndCount + (3 * seg_count + 1) * DataSize::kUSHORT +
+      seg_count * DataSize::kSHORT;
+  return glyph_id_array_offset;
+}
+
+int32_t CMapTable::CMapFormat4::EndCode(int32_t segment) {
+  if (IsValidIndex(segment)) {
+    return EndCode(data_, seg_count_, segment);
+  }
+#if defined (SFNTLY_NO_EXCEPTION)
+  return -1;
+#else
+  throw IllegalArgumentException();
+#endif
+}
+
+bool CMapTable::CMapFormat4::IsValidIndex(int32_t segment) {
+  if (segment < 0 || segment >= seg_count_) {
+#if defined (SFNTLY_NO_EXCEPTION)
+    return false;
+#else
+    throw IllegalArgumentException();
+#endif
+  }
+  return true;
+}
+
+int32_t CMapTable::CMapFormat4::IdDelta(int32_t segment) {
+  if (IsValidIndex(segment))
+    return IdDelta(data_, seg_count_, segment);
+  return -1;
+}
+
+int32_t CMapTable::CMapFormat4::IdRangeOffset(int32_t segment) {
+  if (IsValidIndex(segment))
+    return data_->ReadUShort(IdRangeOffsetLocation(segment));
+  return -1;
+}
+
+int32_t CMapTable::CMapFormat4::IdRangeOffsetLocation(int32_t segment) {
+  if (IsValidIndex(segment))
+    return IdRangeOffsetOffset(seg_count_) + segment * DataSize::kUSHORT;
+  return -1;
+}
+
+int32_t CMapTable::CMapFormat4::GlyphIdArray(int32_t index) {
+  return data_->ReadUShort(glyph_id_array_offset_ + index * DataSize::kUSHORT);
+}
+
+int32_t CMapTable::CMapFormat4::Language() {
+  return Language(data_);
+}
+
+
+CMapTable::CMap::CharacterIterator* CMapTable::CMapFormat4::Iterator() {
+  return new CharacterIterator(this);
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat4::CharacterIterator class
+ ******************************************************************************/
+CMapTable::CMapFormat4::CharacterIterator::CharacterIterator(
+    CMapFormat4* parent)
+    : parent_(parent),
+      segment_index_(0),
+      first_char_in_segment_(-1),
+      last_char_in_segment_(-1),
+      next_char_(-1),
+      next_char_set_(false) {
+}
+
+bool CMapTable::CMapFormat4::CharacterIterator::HasNext() {
+  if (next_char_set_)
+    return true;
+  while (segment_index_ < parent_->seg_count_) {
+    if (first_char_in_segment_ < 0) {
+      first_char_in_segment_ = parent_->StartCode(segment_index_);
+      last_char_in_segment_ = parent_->EndCode(segment_index_);
+      next_char_ = first_char_in_segment_;
+      next_char_set_ = true;
+      return true;
+    }
+    if (next_char_ < last_char_in_segment_) {
+      next_char_++;
+      next_char_set_ = true;
+      return true;
+    }
+    segment_index_++;
+    first_char_in_segment_ = -1;
+  }
+  return false;
+}
+
+int32_t CMapTable::CMapFormat4::CharacterIterator::Next() {
+  if (!next_char_set_) {
+    if (!HasNext()) {
+#if defined (SFNTLY_NO_EXCEPTION)
+      return -1;
+#else
+      throw NoSuchElementException("No more characters to iterate.");
+#endif
+    }
+  }
+  next_char_set_ = false;
+  return next_char_;
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat4::Builder::Segment class
+ ******************************************************************************/
+CMapTable::CMapFormat4::Builder::Segment::Segment() {}
+
+CMapTable::CMapFormat4::Builder::Segment::Segment(Segment* other)
+    : start_count_(other->start_count_),
+      end_count_(other->end_count_),
+      id_delta_(other->id_delta_),
+      id_range_offset_(other->id_range_offset_) {
+}
+
+CMapTable::CMapFormat4::Builder::Segment::Segment(int32_t start_count,
+                                                  int32_t end_count,
+                                                  int32_t id_delta,
+                                                  int32_t id_range_offset)
+    : start_count_(start_count),
+      end_count_(end_count),
+      id_delta_(id_delta),
+      id_range_offset_(id_range_offset) {
+}
+
+CMapTable::CMapFormat4::Builder::Segment::~Segment() {}
+
+int32_t CMapTable::CMapFormat4::Builder::Segment::start_count() {
+  return start_count_;
+}
+
+void
+CMapTable::CMapFormat4::Builder::Segment::set_start_count(int32_t start_count) {
+  start_count_ = start_count;
+}
+
+int32_t CMapTable::CMapFormat4::Builder::Segment::end_count() {
+  return end_count_;
+}
+
+void
+CMapTable::CMapFormat4::Builder::Segment::set_end_count(int32_t end_count) {
+  end_count_ = end_count;
+}
+
+int32_t CMapTable::CMapFormat4::Builder::Segment::id_delta() {
+  return id_delta_;
+}
+
+void
+CMapTable::CMapFormat4::Builder::Segment::set_id_delta(int32_t id_delta) {
+  id_delta_ = id_delta;
+}
+
+int32_t CMapTable::CMapFormat4::Builder::Segment::id_range_offset() {
+  return id_range_offset_;
+}
+
+void
+CMapTable::CMapFormat4::Builder::Segment::
+set_id_range_offset(int32_t id_range_offset) {
+  id_range_offset_ = id_range_offset;
+}
+
+// static
+CALLER_ATTACH SegmentList*
+CMapTable::CMapFormat4::Builder::Segment::DeepCopy(SegmentList* original) {
+  SegmentList* list = new SegmentList;
+  for (SegmentList::iterator it = original->begin(),
+           e = original->end(); it != e; ++it) {
+    list->push_back(*it);
+  }
+  return list;
+}
+
+/******************************************************************************
+ * CMapTable::CMapFormat4::Builder class
+ ******************************************************************************/
+CALLER_ATTACH CMapTable::CMapFormat4::Builder*
+CMapTable::CMapFormat4::Builder::NewInstance(ReadableFontData* data,
+                                             int32_t offset,
+                                             const CMapId& cmap_id) {
+  ReadableFontDataPtr rdata;
+  if (data) {
+    rdata.Attach
+        (down_cast<ReadableFontData*>
+         (data->Slice(offset,
+                      data->ReadUShort(offset + Offset::kFormat4Length))));
+  }
+  return new Builder(rdata, CMapFormat::kFormat4, cmap_id);
+}
+
+CALLER_ATTACH CMapTable::CMapFormat4::Builder*
+CMapTable::CMapFormat4::Builder::NewInstance(WritableFontData* data,
+                                             int32_t offset,
+                                             const CMapId& cmap_id) {
+  WritableFontDataPtr wdata;
+  if (data) {
+    wdata.Attach
+        (down_cast<WritableFontData*>
+         (data->Slice(offset,
+                      data->ReadUShort(offset + Offset::kFormat4Length))));
+  }
+  return new Builder(wdata, CMapFormat::kFormat4, cmap_id);
+}
+
+CALLER_ATTACH CMapTable::CMapFormat4::Builder*
+CMapTable::CMapFormat4::Builder::NewInstance(const CMapId& cmap_id) {
+  return new Builder(cmap_id);
+}
+
+CMapTable::CMapFormat4::Builder::Builder(ReadableFontData* data, int32_t offset,
+                                         const CMapId& cmap_id)
+    : CMap::Builder(data, CMapFormat::kFormat4, cmap_id) {
+  UNREFERENCED_PARAMETER(offset);
+}
+
+CMapTable::CMapFormat4::Builder::Builder(WritableFontData* data, int32_t offset,
+                                         const CMapId& cmap_id)
+    : CMap::Builder(data, CMapFormat::kFormat4, cmap_id) {
+  UNREFERENCED_PARAMETER(offset);
+}
+
+CMapTable::CMapFormat4::Builder::Builder(SegmentList* segments,
+                                         IntegerList* glyph_id_array,
+                                         const CMapId& cmap_id)
+    : CMap::Builder(reinterpret_cast<ReadableFontData*>(NULL),
+                    CMapFormat::kFormat4, cmap_id),
+      segments_(segments->begin(), segments->end()),
+      glyph_id_array_(glyph_id_array->begin(), glyph_id_array->end()) {
+  set_model_changed();
+}
+
+CMapTable::CMapFormat4::Builder::Builder(const CMapId& cmap_id)
+    : CMap::Builder(reinterpret_cast<ReadableFontData*>(NULL),
+                    CMapFormat::kFormat4, cmap_id) {
+}
+
+CMapTable::CMapFormat4::Builder::~Builder() {}
+
+void CMapTable::CMapFormat4::Builder::Initialize(ReadableFontData* data) {
+  if (data == NULL || data->Length() == 0)
+    return;
+
+  // build segments
+  int32_t seg_count = CMapFormat4::SegCount(data);
+  for (int32_t index = 0; index < seg_count; ++index) {
+    Ptr<Segment> segment = new Segment;
+    segment->set_start_count(CMapFormat4::StartCode(data, seg_count, index));
+#if defined SFNTLY_DEBUG_CMAP
+    fprintf(stderr, "Segment %d; start %d\n", index, segment->start_count());
+#endif
+    segment->set_end_count(CMapFormat4::EndCode(data, seg_count, index));
+    segment->set_id_delta(CMapFormat4::IdDelta(data, seg_count, index));
+    segment->set_id_range_offset(CMapFormat4::IdRangeOffset(data,
+                                                           seg_count,
+                                                           index));
+    segments_.push_back(segment);
+  }
+
+  // build glyph id array
+  int32_t glyph_id_array_offset = CMapFormat4::GlyphIdArrayOffset(seg_count);
+  int32_t glyph_id_array_length =
+      (CMapFormat4::Length(data) - glyph_id_array_offset)
+      / DataSize::kUSHORT;
+  fprintf(stderr, "id array size %d\n", glyph_id_array_length);
+  for (int32_t i = 0; i < glyph_id_array_length; i += DataSize::kUSHORT) {
+    glyph_id_array_.push_back(data->ReadUShort(glyph_id_array_offset + i));
+  }
+}
+
+SegmentList* CMapTable::CMapFormat4::Builder::segments() {
+  if (segments_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &segments_;
+}
+
+void CMapTable::CMapFormat4::Builder::set_segments(SegmentList* segments) {
+  segments_.assign(segments->begin(), segments->end());
+  set_model_changed();
+}
+
+IntegerList* CMapTable::CMapFormat4::Builder::glyph_id_array() {
+  if (glyph_id_array_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &glyph_id_array_;
+}
+
+void CMapTable::CMapFormat4::Builder::
+set_glyph_id_array(IntegerList* glyph_id_array) {
+  glyph_id_array_.assign(glyph_id_array->begin(), glyph_id_array->end());
+  set_model_changed();
+}
+
+CALLER_ATTACH FontDataTable*
+CMapTable::CMapFormat4::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new CMapFormat4(data, cmap_id());
+  return table.Detach();
+}
+
+void CMapTable::CMapFormat4::Builder::SubDataSet() {
+  segments_.clear();
+  glyph_id_array_.clear();
+  set_model_changed();
+}
+
+int32_t CMapTable::CMapFormat4::Builder::SubDataSizeToSerialize() {
+  if (!model_changed()) {
+    return CMap::Builder::SubDataSizeToSerialize();
+  }
+  int32_t size = Offset::kFormat4FixedSize + segments_.size()
+      * (3 * DataSize::kUSHORT + DataSize::kSHORT)
+      + glyph_id_array_.size() * DataSize::kSHORT;
+  return size;
+}
+
+bool CMapTable::CMapFormat4::Builder::SubReadyToSerialize() {
+  if (!model_changed()) {
+    return CMap::Builder::SubReadyToSerialize();
+  }
+  if (!segments()->empty()) {
+    return true;
+  }
+  return false;
+}
+
+int32_t
+CMapTable::CMapFormat4::Builder::SubSerialize(WritableFontData* new_data) {
+  if (!model_changed()) {
+    return CMap::Builder::SubSerialize(new_data);
+  }
+  int32_t index = 0;
+  index += new_data->WriteUShort(index, CMapFormat::kFormat4);
+  index += DataSize::kUSHORT;  // length - write this at the end
+  index += new_data->WriteUShort(index, language());
+
+  int32_t seg_count = segments_.size();
+  index += new_data->WriteUShort(index, seg_count * 2);
+  int32_t log2_seg_count = FontMath::Log2(seg_count);
+  int32_t search_range = 1 << (log2_seg_count + 1);
+  index += new_data->WriteUShort(index, search_range);
+  int32_t entry_selector = log2_seg_count;
+  index += new_data->WriteUShort(index, entry_selector);
+  int32_t range_shift = 2 * seg_count - search_range;
+  index += new_data->WriteUShort(index, range_shift);
+
+  for (int32_t i = 0; i < seg_count; ++i) {
+    index += new_data->WriteUShort(index, segments_[i]->end_count());
+  }
+  index += new_data->WriteUShort(index, 0);  // reserved ushort
+  for (int32_t i = 0; i < seg_count; ++i) {
+#if defined SFNTLY_DEBUG_CMAP
+    fprintf(stderr, "Segment %d; start %d\n", i, segments_[i]->start_count());
+#endif
+    index += new_data->WriteUShort(index, segments_[i]->start_count());
+  }
+  for (int32_t i = 0; i < seg_count; ++i) {
+    index += new_data->WriteShort(index, segments_[i]->id_delta());
+  }
+  for (int32_t i = 0; i < seg_count; ++i) {
+    index += new_data->WriteUShort(index, segments_[i]->id_range_offset());
+  }
+
+#if defined SFNTLY_DEBUG_CMAP
+  fprintf(stderr, "Glyph id array size %lu\n", glyph_id_array_.size());
+#endif
+  for (size_t i = 0; i < glyph_id_array_.size(); ++i) {
+    index += new_data->WriteUShort(index, glyph_id_array_[i]);
+  }
+
+  new_data->WriteUShort(Offset::kFormat4Length, index);
+  return index;
+}
+
+/******************************************************************************
+ * CMapTable::Builder class
+ ******************************************************************************/
+CMapTable::Builder::Builder(Header* header, WritableFontData* data)
+    : SubTableContainerTable::Builder(header, data), version_(0) {
+}
+
+CMapTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : SubTableContainerTable::Builder(header, data), version_(0) {
+}
+
+CMapTable::Builder::~Builder() {
+}
+
+int32_t CMapTable::Builder::SubSerialize(WritableFontData* new_data) {
+  int32_t size = new_data->WriteUShort(CMapTable::Offset::kVersion,
+                                       version_);
+  size += new_data->WriteUShort(CMapTable::Offset::kNumTables,
+                                GetCMapBuilders()->size());
+
+  int32_t index_offset = size;
+  size += GetCMapBuilders()->size() * CMapTable::Offset::kEncodingRecordSize;
+  for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(),
+           e = GetCMapBuilders()->end(); it != e; ++it) {
+    CMapBuilderPtr b = it->second;
+    // header entry
+    index_offset += new_data->WriteUShort(index_offset, b->platform_id());
+    index_offset += new_data->WriteUShort(index_offset, b->encoding_id());
+    index_offset += new_data->WriteULong(index_offset, size);
+
+    // cmap
+    FontDataPtr slice;
+    slice.Attach(new_data->Slice(size));
+    size += b->SubSerialize(down_cast<WritableFontData*>(slice.p_));
+  }
+  return size;
+}
+
+bool CMapTable::Builder::SubReadyToSerialize() {
+  if (GetCMapBuilders()->empty())
+    return false;
+
+  // check each table
+  for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(),
+           e = GetCMapBuilders()->end(); it != e; ++it) {
+    if (!it->second->SubReadyToSerialize())
+      return false;
+  }
+  return true;
+}
+
+int32_t CMapTable::Builder::SubDataSizeToSerialize() {
+  if (GetCMapBuilders()->empty())
+    return 0;
+
+  bool variable = false;
+  int32_t size = CMapTable::Offset::kEncodingRecordStart +
+      GetCMapBuilders()->size() * CMapTable::Offset::kEncodingRecordSize;
+
+  // calculate size of each table
+  for (CMapBuilderMap::iterator it = GetCMapBuilders()->begin(),
+           e = GetCMapBuilders()->end(); it != e; ++it) {
+    int32_t cmap_size = it->second->SubDataSizeToSerialize();
+    size += abs(cmap_size);
+    variable |= cmap_size <= 0;
+  }
+  return variable ? -size : size;
+}
+
+void CMapTable::Builder::SubDataSet() {
+  GetCMapBuilders()->clear();
+  Table::Builder::set_model_changed();
+}
+
+CALLER_ATTACH FontDataTable*
+    CMapTable::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new CMapTable(header(), data);
+  return table.Detach();
+}
+
+CALLER_ATTACH CMapTable::Builder*
+    CMapTable::Builder::CreateBuilder(Header* header,
+                                      WritableFontData* data) {
+  Ptr<CMapTable::Builder> builder;
+  builder = new CMapTable::Builder(header, data);
+  return builder.Detach();
+}
+
+// static
+CALLER_ATTACH CMapTable::CMap::Builder*
+    CMapTable::Builder::CMapBuilder(ReadableFontData* data, int32_t index) {
+  if (index < 0 || index > NumCMaps(data)) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException(
+              "CMap table is outside of the bounds of the known tables.");
+#endif
+    return NULL;
+  }
+
+  int32_t platform_id = data->ReadUShort(Offset::kEncodingRecordPlatformId +
+                                         OffsetForEncodingRecord(index));
+  int32_t encoding_id = data->ReadUShort(Offset::kEncodingRecordEncodingId +
+                                         OffsetForEncodingRecord(index));
+  int32_t offset = data->ReadULongAsInt(Offset::kEncodingRecordOffset +
+                                        OffsetForEncodingRecord(index));
+  return CMap::Builder::GetBuilder(data, offset,
+                                   NewCMapId(platform_id, encoding_id));
+}
+
+// static
+int32_t CMapTable::Builder::NumCMaps(ReadableFontData* data) {
+  if (data == NULL) {
+    return 0;
+  }
+  return data->ReadUShort(Offset::kNumTables);
+}
+
+int32_t CMapTable::Builder::NumCMaps() {
+  return GetCMapBuilders()->size();
+}
+
+void CMapTable::Builder::Initialize(ReadableFontData* data) {
+  int32_t num_cmaps = NumCMaps(data);
+  for (int32_t i = 0; i < num_cmaps; ++i) {
+    CMapTable::CMap::Builder* cmap_builder = CMapBuilder(data, i);
+    if (!cmap_builder)
+      continue;
+    cmap_builders_[cmap_builder->cmap_id()] = cmap_builder;
+  }
+}
+
+CMapTable::CMap::Builder* CMapTable::Builder::NewCMapBuilder(
+    const CMapId& cmap_id,
+    ReadableFontData* data) {
+  Ptr<WritableFontData> wfd;
+  wfd.Attach(WritableFontData::CreateWritableFontData(data->Size()));
+  data->CopyTo(wfd.p_);
+  CMapTable::CMapBuilderPtr builder;
+  builder.Attach(CMap::Builder::GetBuilder(wfd.p_, 0, cmap_id));
+  CMapBuilderMap* cmap_builders = CMapTable::Builder::GetCMapBuilders();
+  cmap_builders->insert(std::make_pair(cmap_id, builder.p_));
+  return builder.Detach();
+}
+
+CMapTable::CMap::Builder*
+CMapTable::Builder::NewCMapBuilder(int32_t format, const CMapId& cmap_id) {
+  Ptr<CMapTable::CMap::Builder> cmap_builder;
+  cmap_builder.Attach(CMap::Builder::GetBuilder(format, cmap_id));
+  CMapBuilderMap* cmap_builders = CMapTable::Builder::GetCMapBuilders();
+  cmap_builders->insert(std::make_pair(cmap_id, cmap_builder.p_));
+  return cmap_builder.Detach();
+}
+
+CMapTable::CMap::Builder*
+CMapTable::Builder::CMapBuilder(const CMapId& cmap_id) {
+  CMapBuilderMap* cmap_builders = this->GetCMapBuilders();
+  CMapBuilderMap::iterator builder = cmap_builders->find(cmap_id);
+  if (builder != cmap_builders->end())
+    return builder->second;
+#ifndef SFNTLY_NO_EXCEPTION
+  throw NoSuchElementException("No builder found for cmap_id");
+#else
+  return NULL;
+#endif
+}
+
+CMapTable::CMapBuilderMap* CMapTable::Builder::GetCMapBuilders() {
+  if (cmap_builders_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &cmap_builders_;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/core/cmap_table.h b/cpp/src/sfntly/table/core/cmap_table.h
new file mode 100644
index 0000000..b264b07
--- /dev/null
+++ b/cpp/src/sfntly/table/core/cmap_table.h
@@ -0,0 +1,709 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_
+
+// type.h needs to be included first because of building issues on Windows
+// Type aliases we delcare are defined in other headers and make the build
+// fail otherwise.
+#include "sfntly/port/type.h"
+#include <vector>
+#include <map>
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/table/subtable.h"
+#include "sfntly/table/subtable_container_table.h"
+
+namespace sfntly {
+
+// CMap subtable formats
+struct CMapFormat {
+  enum {
+    kFormat0 = 0,
+    kFormat2 = 2,
+    kFormat4 = 4,
+    kFormat6 = 6,
+    kFormat8 = 8,
+    kFormat10 = 10,
+    kFormat12 = 12,
+    kFormat13 = 13,
+    kFormat14 = 14
+  };
+};
+
+// A CMap table
+class CMapTable : public SubTableContainerTable, public RefCounted<CMapTable> {
+public:
+  // CMapTable::CMapId
+  struct CMapId {
+    int32_t platform_id;
+    int32_t encoding_id;
+    bool operator==(const CMapId& obj) const {
+      return platform_id == obj.platform_id && encoding_id == obj.encoding_id;
+    }
+  };
+  static CMapId WINDOWS_BMP;
+  static CMapId WINDOWS_UCS4;
+  static CMapId MAC_ROMAN;
+
+  // CMapTable::CMapIdComparator
+  class CMapIdComparator {
+   public:
+    bool operator()(const CMapId& lhs, const CMapId& rhs) const;
+  };
+
+  // A filter on cmap
+  // CMapTable::CMapFilter
+  class CMapFilter {
+   public:
+    // Test on whether the cmap is acceptable or not
+    // @param cmap_id the id of the cmap
+    // @return true if the cmap is acceptable; false otherwise
+    virtual bool accept(const CMapId& cmap_id) const = 0;
+    // Make gcc -Wnon-virtual-dtor happy.
+    virtual ~CMapFilter() {}
+  };
+
+  // Filters CMaps by CMapId to implement CMapTable::get()
+  // wanted_id is the CMap we'd like to find.
+  // We compare the current CMap to it either by equality (==) or using a
+  // comparator.
+  // CMapTable::CMapIdFilter
+  class CMapIdFilter : public CMapFilter {
+   public:
+    explicit CMapIdFilter(const CMapId wanted_id);
+    CMapIdFilter(const CMapId wanted_id,
+                 const CMapIdComparator* comparator);
+    ~CMapIdFilter() {}
+    virtual bool accept(const CMapId& cmap_id) const;
+   private:
+    CMapIdFilter& operator=(const CMapIdFilter& that);
+    const CMapId wanted_id_;
+    const CMapIdComparator *comparator_;
+  };
+
+  // The abstract base class for all cmaps.
+  //
+  // CMap equality is based on the equality of the (@link {@link CMapId} that
+  // defines the CMap. In the cmap table for a font there can only be one cmap
+  // with a given cmap id (pair of platform and encoding ids) no matter what the
+  // type of the cmap is.
+  //
+  // The cmap offers CharacterIterator to allow iteration over
+  // characters that are mapped by the cmap. This iteration mostly returns the
+  // characters mapped by the cmap. It will return all characters mapped by the
+  // cmap to anything but .notdef <b>but</b> it may return some that are not
+  // mapped or are mapped to .notdef. Various cmap tables provide ranges and
+  // such to describe characters for lookup but without going the full way to
+  // mapping to the glyph id it isn't always possible to tell if a character
+  // will end up with a valid glyph id. So, some of the characters returned from
+  // the Iterator may still end up pointing to the .notdef glyph. However, the
+  // number of such characters should be small in most cases with well designed
+  // cmaps.
+  class Builder;
+  class CMap : public SubTable {
+   public:
+    // CMapTable::CMap::Builder
+    class Builder : public SubTable::Builder {
+     public:
+      virtual ~Builder();
+
+      CALLER_ATTACH static Builder*
+          GetBuilder(ReadableFontData* data,
+                     int32_t offset,
+                     const CMapId& cmap_id);
+      CALLER_ATTACH static Builder*
+          GetBuilder(int32_t format,
+                     const CMapId& cmap_id);
+
+      // Note: yes, an object is returned on stack since it's small enough.
+      virtual CMapId cmap_id() { return cmap_id_; }
+      virtual int32_t platform_id() { return cmap_id_.platform_id; }
+      virtual int32_t encoding_id() { return cmap_id_.encoding_id; }
+      virtual int32_t format() { return format_; }
+      virtual int32_t language() { return language_; }
+      virtual void set_language(int32_t language) { language_ = language; }
+
+     protected:
+      Builder(ReadableFontData* data,
+              int32_t format,
+              const CMapId& cmap_id);
+      Builder(WritableFontData* data,
+              int32_t format,
+              const CMapId& cmap_id);
+
+      virtual int32_t SubSerialize(WritableFontData* new_data);
+      virtual bool SubReadyToSerialize();
+      virtual int32_t SubDataSizeToSerialize();
+      virtual void SubDataSet();
+
+     private:
+      int32_t format_;
+      CMapId cmap_id_;
+      int32_t language_;
+
+      friend class CMapTable::Builder;
+    };
+    // Abstract CMap character iterator
+    // The fully qualified name is CMapTable::CMap::CharacterIterator
+    class CharacterIterator {
+     public:
+      virtual ~CharacterIterator() {}
+      virtual bool HasNext() = 0;
+      // Returns -1 if there are no more characters to iterate through
+      // and exceptions are turned off
+      virtual int32_t Next() = 0;
+
+     protected:
+      // Use the CMap::Iterator method below instead of directly requesting
+      // a CharacterIterator.
+      CharacterIterator() {}
+    };
+
+    CMap(ReadableFontData* data, int32_t format, const CMapId& cmap_id);
+    virtual ~CMap();
+
+    virtual CMap::CharacterIterator* Iterator() = 0;
+
+    virtual int32_t format() { return format_; }
+    virtual CMapId cmap_id() { return cmap_id_; }
+    virtual int32_t platform_id() { return cmap_id_.platform_id; }
+    virtual int32_t encoding_id() { return cmap_id_.encoding_id; }
+
+    // Get the language of the cmap.
+    //
+    // Note on the language field in 'cmap' subtables: The language field must
+    // be set to zero for all cmap subtables whose platform IDs are other than
+    // Macintosh (platform ID 1). For cmap subtables whose platform IDs are
+    // Macintosh, set this field to the Macintosh language ID of the cmap
+    // subtable plus one, or to zero if the cmap subtable is not
+    // language-specific. For example, a Mac OS Turkish cmap subtable must set
+    // this field to 18, since the Macintosh language ID for Turkish is 17. A
+    // Mac OS Roman cmap subtable must set this field to 0, since Mac OS Roman
+    // is not a language-specific encoding.
+    //
+    // @return the language id
+    virtual int32_t Language() = 0;
+
+    // Gets the glyph id for the character code provided.
+    // The character code provided must be in the encoding used by the cmap
+    // table.
+    virtual int32_t GlyphId(int32_t character) = 0;
+
+   private:
+    int32_t format_;
+    CMapId cmap_id_;
+  };
+  typedef Ptr<CMap> CMapPtr;
+  typedef Ptr<CMap::Builder> CMapBuilderPtr;
+  typedef std::map<CMapId, CMapBuilderPtr, CMapIdComparator> CMapBuilderMap;
+
+  // A cmap format 0 sub table
+  class CMapFormat0 : public CMap, public RefCounted<CMapFormat0> {
+   public:
+    // The fully qualified name is CMapTable::CMapFormat0::Builder
+    class Builder : public CMap::Builder,
+                    public RefCounted<Builder> {
+     public:
+      CALLER_ATTACH static Builder* NewInstance(ReadableFontData* data,
+                                                int32_t offset,
+                                                const CMapId& cmap_id);
+      CALLER_ATTACH static Builder* NewInstance(WritableFontData* data,
+                                                int32_t offset,
+                                                const CMapId& cmap_id);
+      CALLER_ATTACH static Builder* NewInstance(const CMapId& cmap_id);
+      virtual ~Builder();
+
+     protected:
+      virtual CALLER_ATTACH FontDataTable*
+          SubBuildTable(ReadableFontData* data);
+
+     private:
+      // When creating a new CMapFormat0 Builder, use NewInstance instead of
+      // the constructors! This avoids a memory leak when slicing the FontData.
+      Builder(ReadableFontData* data, int32_t offset, const CMapId& cmap_id);
+      Builder(WritableFontData* data, int32_t offset, const CMapId& cmap_id);
+      Builder(const CMapId& cmap_id);
+    };
+
+    // The fully qualified name is CMapTable::CMapFormat0::CharacterIterator
+    class CharacterIterator : public CMap::CharacterIterator {
+     public:
+      virtual ~CharacterIterator();
+      virtual bool HasNext();
+      virtual int32_t Next();
+
+     private:
+      CharacterIterator(int32_t start, int32_t end);
+      friend class CMapFormat0;
+      int32_t character_, max_character_;
+    };
+
+    virtual ~CMapFormat0();
+    virtual int32_t Language();
+    virtual int32_t GlyphId(int32_t character);
+    CMap::CharacterIterator* Iterator();
+
+   private:
+    CMapFormat0(ReadableFontData* data, const CMapId& cmap_id);
+  };
+
+  // A cmap format 2 sub table
+  // The format 2 cmap is used for multi-byte encodings such as SJIS,
+  // EUC-JP/KR/CN, Big5, etc.
+  class CMapFormat2 : public CMap, public RefCounted<CMapFormat2> {
+   public:
+    // CMapTable::CMapFormat2::Builder
+    class Builder : public CMap::Builder,
+                    public RefCounted<Builder> {
+     public:
+      Builder(ReadableFontData* data,
+              int32_t offset,
+              const CMapId& cmap_id);
+      Builder(WritableFontData* data,
+              int32_t offset,
+              const CMapId& cmap_id);
+      virtual ~Builder();
+
+     protected:
+      virtual CALLER_ATTACH FontDataTable*
+          SubBuildTable(ReadableFontData* data);
+    };
+    // CMapTable::CMapFormat2::CharacterIterator
+    class CharacterIterator : public CMap::CharacterIterator {
+     public:
+      virtual ~CharacterIterator();
+      virtual bool hasNext();
+      virtual int32_t next();
+
+     private:
+      CharacterIterator();
+    };
+
+    virtual int32_t Language();
+    virtual int32_t GlyphId(int32_t character);
+
+    // Returns how many bytes would be consumed by a lookup of this character
+    // with this cmap. This comes about because the cmap format 2 table is
+    // designed around multi-byte encodings such as SJIS, EUC-JP, Big5, etc.
+    // return the number of bytes consumed from this "character" - either 1 or 2
+    virtual int32_t BytesConsumed(int32_t character);
+
+    virtual ~CMapFormat2();
+
+   private:
+    CMapFormat2(ReadableFontData* data, const CMapId& cmap_id);
+
+    int32_t SubHeaderOffset(int32_t sub_header_index);
+    int32_t FirstCode(int32_t sub_header_index);
+    int32_t EntryCount(int32_t sub_header_index);
+    int32_t IdRangeOffset(int32_t sub_header_index);
+    int32_t IdDelta(int32_t sub_header_index);
+    CMap::CharacterIterator* Iterator();
+  };
+
+    // CMapTable::CMapFormat4
+  class CMapFormat4 : public CMap,
+                      public RefCounted<CMapFormat4> {
+   public:
+    // CMapTable::CMapFormat4::Builder
+    class Builder : public CMap::Builder,
+                    public RefCounted<Builder> {
+     public:
+        // CMapTable::CMapFormat4::Builder::Segment
+      class Segment : public RefCounted<Segment> {
+       public:
+        Segment();
+        explicit Segment(Segment* other);
+        Segment(int32_t start_count,
+                int32_t end_count,
+                int32_t id_delta,
+                int32_t id_range_offset);
+        ~Segment();
+
+        // @return the startCount
+        int32_t start_count();
+        // @param startCount the startCount to set
+        void set_start_count(int32_t start_count);
+        // @return the endCount
+        int32_t end_count();
+        // @param endcount the endCount to set
+        void set_end_count(int32_t end_count);
+        // @return the idDelta
+        int32_t id_delta();
+        // @param idDelta the idDelta to set
+        void set_id_delta(int32_t id_delta);
+        // @return the idRangeOffset
+        int32_t id_range_offset();
+        // @param idRangeOffset the idRangeOffset to set
+        void set_id_range_offset(int32_t id_range_offset);
+
+        static CALLER_ATTACH
+        std::vector<Ptr<Segment> >*
+        DeepCopy(std::vector<Ptr<Segment> >* original);
+
+       private:
+        int32_t start_count_;
+        int32_t end_count_;
+        int32_t id_delta_;
+        int32_t id_range_offset_;
+      };
+      typedef std::vector<Ptr<Segment> > SegmentList;
+
+      static CALLER_ATTACH Builder* NewInstance(WritableFontData* data,
+                                                int32_t offset,
+                                                const CMapId& cmap_id);
+      static CALLER_ATTACH Builder* NewInstance(ReadableFontData* data,
+                                                int32_t offset,
+                                                const CMapId& cmap_id);
+      static CALLER_ATTACH Builder* NewInstance(const CMapId& cmap_id);
+      virtual ~Builder();
+      SegmentList* segments();
+      void set_segments(SegmentList* segments);
+      IntegerList* glyph_id_array();
+      void set_glyph_id_array(IntegerList* glyph_id_array);
+
+     protected:
+      Builder(WritableFontData* data, int32_t offset, const CMapId& cmap_id);
+      Builder(ReadableFontData* data, int32_t offset, const CMapId& cmap_id);
+      Builder(SegmentList* segments, IntegerList* glyph_id_array,
+              const CMapId& cmap_id);
+      explicit Builder(const CMapId& cmap_id);
+
+      virtual CALLER_ATTACH FontDataTable* SubBuildTable(
+          ReadableFontData* data);
+      virtual void SubDataSet();
+      virtual int32_t SubDataSizeToSerialize();
+      virtual bool SubReadyToSerialize();
+      virtual int32_t SubSerialize(WritableFontData* new_data);
+
+     private:
+      void Initialize(ReadableFontData* data);
+
+      SegmentList segments_;
+      IntegerList glyph_id_array_;
+    };
+
+    CMap::CharacterIterator* Iterator();
+    // CMapTable::CMapFormat4::CharacterIterator
+    class CharacterIterator : public CMap::CharacterIterator {
+     public:
+      bool HasNext();
+      int32_t Next();
+      virtual ~CharacterIterator() {}
+
+     private:
+      explicit CharacterIterator(CMapFormat4 *parent);
+      friend CMap::CharacterIterator* CMapFormat4::Iterator();
+
+      CMapFormat4* parent_;
+      int32_t segment_index_;
+      int32_t first_char_in_segment_;
+      int32_t last_char_in_segment_;
+      int32_t next_char_;
+      bool next_char_set_;
+    };
+
+    virtual int32_t GlyphId(int32_t character);
+
+    // Lower level glyph code retrieval that requires processing the Format 4
+    // segments to use.
+    // @param segment the cmap segment
+    // @param startCode the start code for the segment
+    // @param character the character to be looked up
+    // @return the glyph id for the character; CMapTable.NOTDEF if not found
+    int32_t RetrieveGlyphId(int32_t segment,
+                            int32_t start_count,
+                            int32_t character);
+    virtual int32_t Language();
+
+    // Get the count of the number of segments in this cmap.
+    // @return the number of segments
+    int32_t seg_count();
+    int32_t Length();
+    // Get the start code for a segment.
+    // @param segment the segment in the lookup table
+    // @return the start code for a segment
+    int32_t StartCode(int32_t segment);
+    // Get the end code for a segment.
+    // @param segment the segment in the look up table
+    // @return the end code for the segment
+    int32_t EndCode(int32_t segment);
+    // Get the id delta for a segment
+    // @param segment the segment in the look up table
+    // @return the id delta for the segment
+    int32_t IdDelta(int32_t segment);
+    // Get the id range offset for a segment
+    // @param segment the segment in the look up table
+    // @return the id range offset for the segment
+    int32_t IdRangeOffset(int32_t segment);
+    // Get the location of the id range offset for a segment
+    // @param segment the segment in the look up table
+    // @return the location of the id range offset for the segment
+    int32_t IdRangeOffsetLocation(int32_t segment);
+    // Declared above to allow friending inside CharacterIterator class.
+    // CMap::CharacterIterator* Iterator();
+    virtual ~CMapFormat4();
+
+   protected:
+    CMapFormat4(ReadableFontData* data, const CMapId& cmap_id);
+
+   private:
+    static int32_t Language(ReadableFontData* data);
+    static int32_t Length(ReadableFontData* data);
+    static int32_t SegCount(ReadableFontData* data);
+    static int32_t StartCode(ReadableFontData* data,
+                             int32_t seg_count,
+                             int32_t index);
+    static int32_t StartCodeOffset(int32_t seg_count);
+    static int32_t EndCode(ReadableFontData* data,
+                           int32_t seg_count,
+                           int32_t index);
+    static int32_t IdDelta(ReadableFontData* data,
+                           int32_t seg_count,
+                           int32_t index);
+    static int32_t IdDeltaOffset(int32_t seg_count);
+    static int32_t IdRangeOffset(ReadableFontData* data,
+                                 int32_t seg_count,
+                                 int32_t index);
+    static int32_t IdRangeOffsetOffset(int32_t seg_count);
+    static int32_t GlyphIdArrayOffset(int32_t seg_count);
+    // Refactored void to bool to work without exceptions.
+    bool IsValidIndex(int32_t segment);
+    int32_t GlyphIdArray(int32_t index);
+
+    int32_t seg_count_;
+    int32_t start_code_offset_;
+    int32_t id_delta_offset_;
+    int32_t glyph_id_array_offset_;
+  };
+
+  // CMapTable::Builder
+  class Builder : public SubTableContainerTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    // Constructor scope is public because C++ does not allow base class to
+    // instantiate derived class with protected constructors.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual void SubDataSet();
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+
+    CMap::Builder* NewCMapBuilder(const CMapId& cmap_id,
+                                  ReadableFontData* data);
+    // Create a new empty CMapBuilder of the type specified in the id.
+    CMap::Builder* NewCMapBuilder(int32_t format, const CMapId& cmap_id);
+    CMap::Builder* CMapBuilder(const CMapId& cmap_id);
+
+    int32_t NumCMaps();
+    void SetVersion(int32_t version);
+
+    CMapBuilderMap* GetCMapBuilders();
+
+   protected:
+    static CALLER_ATTACH CMap::Builder* CMapBuilder(ReadableFontData* data,
+                                                    int32_t index);
+
+   private:
+    void Initialize(ReadableFontData* data);
+    static int32_t NumCMaps(ReadableFontData* data);
+
+    int32_t version_;
+    CMapBuilderMap cmap_builders_;
+  };
+  typedef Ptr<Builder> CMapTableBuilderPtr;
+
+  class CMapIterator {
+   public:
+    // If filter is NULL, filter through all tables.
+    CMapIterator(CMapTable* table, const CMapFilter* filter);
+    bool HasNext();
+    CMap* Next();
+
+   private:
+    int32_t table_index_;
+    const CMapFilter* filter_;
+    CMapTable* table_;
+  };
+
+  // Make a CMapId from a platform_id, encoding_id pair
+  static CMapId NewCMapId(int32_t platform_id, int32_t encoding_id);
+  // Make a CMapId from another CMapId
+  static CMapId NewCMapId(const CMapId& obj);
+
+  // Get the CMap with the specified parameters if it exists.
+  // Returns NULL otherwise.
+  CALLER_ATTACH CMap* GetCMap(const int32_t index);
+  CALLER_ATTACH CMap* GetCMap(const int32_t platform_id,
+                              const int32_t encoding_id);
+  CALLER_ATTACH CMap* GetCMap(const CMapId GetCMap_id);
+
+  // Get the table version.
+  virtual int32_t Version();
+
+  // Get the number of cmaps within the CMap table.
+  virtual int32_t NumCMaps();
+
+  // Get the cmap id for the cmap with the given index.
+  // Note: yes, an object is returned on stack since it's small enough.
+  //       This function is renamed from cmapId to GetCMapId().
+  virtual CMapId GetCMapId(int32_t index);
+
+  virtual int32_t PlatformId(int32_t index);
+  virtual int32_t EncodingId(int32_t index);
+
+  // Get the offset in the table data for the cmap table with the given index.
+  // The offset is from the beginning of the table.
+  virtual int32_t Offset(int32_t index);
+
+  virtual ~CMapTable();
+
+  static const int32_t NOTDEF;
+
+ private:
+  // Offsets to specific elements in the underlying data. These offsets are
+  // relative to the start of the table or the start of sub-blocks within
+  // the table.
+  struct Offset {
+    enum {
+      kVersion = 0,
+      kNumTables = 2,
+      kEncodingRecordStart = 4,
+
+      // offsets relative to the encoding record
+      kEncodingRecordPlatformId = 0,
+      kEncodingRecordEncodingId = 2,
+      kEncodingRecordOffset = 4,
+      kEncodingRecordSize = 8,
+
+      kFormat = 0,
+
+      // Format 0: Byte encoding table
+      kFormat0Format = 0,
+      kFormat0Length = 2,
+      kFormat0Language = 4,
+      kFormat0GlyphIdArray = 6,
+
+      // Format 2: High-byte mapping through table
+      kFormat2Format = 0,
+      kFormat2Length = 2,
+      kFormat2Language = 4,
+      kFormat2SubHeaderKeys = 6,
+      kFormat2SubHeaders = 518,
+      // offset relative to the subHeader structure
+      kFormat2SubHeader_firstCode = 0,
+      kFormat2SubHeader_entryCount = 2,
+      kFormat2SubHeader_idDelta = 4,
+      kFormat2SubHeader_idRangeOffset = 6,
+      kFormat2SubHeader_structLength = 8,
+
+      // Format 4: Segment mapping to delta values
+      kFormat4Format = 0,
+      kFormat4Length = 2,
+      kFormat4Language = 4,
+      kFormat4SegCountX2 = 6,
+      kFormat4SearchRange = 8,
+      kFormat4EntrySelector = 10,
+      kFormat4RangeShift = 12,
+      kFormat4EndCount = 14,
+      kFormat4FixedSize = 16,
+
+      // format 6: Trimmed table mapping
+      kFormat6Format = 0,
+      kFormat6Length = 2,
+      kFormat6Language = 4,
+      kFormat6FirstCode = 6,
+      kFormat6EntryCount = 8,
+      kFormat6GlyphIdArray = 10,
+
+      // Format 8: mixed 16-bit and 32-bit coverage
+      kFormat8Format = 0,
+      kFormat8Length = 4,
+      kFormat8Language = 8,
+      kFormat8Is32 = 12,
+      kFormat8nGroups204 = 8204,
+      kFormat8Groups208 = 8208,
+      // offset relative to the group structure
+      kFormat8Group_startCharCode = 0,
+      kFormat8Group_endCharCode = 4,
+      kFormat8Group_startGlyphId = 8,
+      kFormat8Group_structLength = 12,
+
+      // Format 10: Trimmed array
+      kFormat10Format = 0,
+      kFormat10Length = 4,
+      kFormat10Language = 8,
+      kFormat10StartCharCode = 12,
+      kFormat10NumChars = 16,
+      kFormat10Glyphs0 = 20,
+
+      // Format 12: Segmented coverage
+      kFormat12Format = 0,
+      kFormat12Length = 4,
+      kFormat12Language = 8,
+      kFormat12nGroups = 12,
+      kFormat12Groups = 16,
+      kFormat12Groups_structLength = 12,
+      // offsets within the group structure
+      kFormat12_startCharCode = 0,
+      kFormat12_endCharCode = 4,
+      kFormat12_startGlyphId = 8,
+
+      // Format 13: Last Resort Font
+      kFormat13Format = 0,
+      kFormat13Length = 4,
+      kFormat13Language = 8,
+      kFormat13nGroups = 12,
+      kFormat13Groups = 16,
+      kFormat13Groups_structLength = 12,
+      // offsets within the group structure
+      kFormat13_startCharCode = 0,
+      kFormat13_endCharCode = 4,
+      kFormat13_glyphId = 8,
+
+      // Format 14: Unicode Variation Sequences
+      kFormat14Format = 0,
+      kFormat14Length = 2,
+
+      // TODO(stuartg): finish tables
+      // Default UVS Table
+
+      // Non-default UVS Table
+      kLast = -1
+    };
+  };
+
+  CMapTable(Header* header, ReadableFontData* data);
+
+  // Get the offset in the table data for the encoding record for the cmap with
+  // the given index. The offset is from the beginning of the table.
+  static int32_t OffsetForEncodingRecord(int32_t index);
+};
+typedef std::vector<CMapTable::CMapId> CMapIdList;
+typedef Ptr<CMapTable> CMapTablePtr;
+typedef std::vector<Ptr<CMapTable::CMapFormat4::Builder::Segment> > SegmentList;
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_CMAP_TABLE_H_
diff --git a/cpp/src/sfntly/table/core/font_header_table.cc b/cpp/src/sfntly/table/core/font_header_table.cc
new file mode 100644
index 0000000..60015ca
--- /dev/null
+++ b/cpp/src/sfntly/table/core/font_header_table.cc
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/core/font_header_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * FontHeaderTable class
+ ******************************************************************************/
+FontHeaderTable::~FontHeaderTable() {}
+
+int32_t FontHeaderTable::TableVersion() {
+  return data_->ReadFixed(Offset::kTableVersion);
+}
+
+int32_t FontHeaderTable::FontRevision() {
+  return data_->ReadFixed(Offset::kFontRevision);
+}
+
+int64_t FontHeaderTable::ChecksumAdjustment() {
+  return data_->ReadULong(Offset::kCheckSumAdjustment);
+}
+
+int64_t FontHeaderTable::MagicNumber() {
+  return data_->ReadULong(Offset::kMagicNumber);
+}
+
+int32_t FontHeaderTable::FlagsAsInt() {
+  return data_->ReadUShort(Offset::kFlags);
+}
+
+int32_t FontHeaderTable::UnitsPerEm() {
+  return data_->ReadUShort(Offset::kUnitsPerEm);
+}
+
+int64_t FontHeaderTable::Created() {
+  return data_->ReadDateTimeAsLong(Offset::kCreated);
+}
+
+int64_t FontHeaderTable::Modified() {
+  return data_->ReadDateTimeAsLong(Offset::kModified);
+}
+
+int32_t FontHeaderTable::XMin() {
+  return data_->ReadUShort(Offset::kXMin);
+}
+
+int32_t FontHeaderTable::YMin() {
+  return data_->ReadUShort(Offset::kYMin);
+}
+
+int32_t FontHeaderTable::XMax() {
+  return data_->ReadUShort(Offset::kXMax);
+}
+
+int32_t FontHeaderTable::YMax() {
+  return data_->ReadUShort(Offset::kYMax);
+}
+
+int32_t FontHeaderTable::MacStyleAsInt() {
+  return data_->ReadUShort(Offset::kMacStyle);
+}
+
+int32_t FontHeaderTable::LowestRecPPEM() {
+  return data_->ReadUShort(Offset::kLowestRecPPEM);
+}
+
+int32_t FontHeaderTable::FontDirectionHint() {
+  return data_->ReadShort(Offset::kFontDirectionHint);
+}
+
+int32_t FontHeaderTable::IndexToLocFormat() {
+  return data_->ReadShort(Offset::kIndexToLocFormat);
+}
+
+int32_t FontHeaderTable::GlyphDataFormat() {
+  return data_->ReadShort(Offset::kGlyphDataFormat);
+}
+
+FontHeaderTable::FontHeaderTable(Header* header, ReadableFontData* data)
+    : Table(header, data) {
+  IntegerList checksum_ranges;
+  checksum_ranges.push_back(0);
+  checksum_ranges.push_back(Offset::kCheckSumAdjustment);
+  checksum_ranges.push_back(Offset::kMagicNumber);
+  data_->SetCheckSumRanges(checksum_ranges);
+}
+
+/******************************************************************************
+ * FontHeaderTable::Builder class
+ ******************************************************************************/
+FontHeaderTable::Builder::Builder(Header* header, WritableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+FontHeaderTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+FontHeaderTable::Builder::~Builder() {}
+
+CALLER_ATTACH FontDataTable* FontHeaderTable::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  FontDataTablePtr table = new FontHeaderTable(header(), data);
+  return table.Detach();
+}
+
+int32_t FontHeaderTable::Builder::TableVersion() {
+  return down_cast<FontHeaderTable*>(GetTable())->TableVersion();
+}
+
+void FontHeaderTable::Builder::SetTableVersion(int32_t version) {
+  InternalWriteData()->WriteFixed(Offset::kTableVersion, version);
+}
+
+int32_t FontHeaderTable::Builder::FontRevision() {
+  return down_cast<FontHeaderTable*>(GetTable())->FontRevision();
+}
+
+void FontHeaderTable::Builder::SetFontRevision(int32_t revision) {
+  InternalWriteData()->WriteFixed(Offset::kFontRevision, revision);
+}
+
+int64_t FontHeaderTable::Builder::ChecksumAdjustment() {
+  return down_cast<FontHeaderTable*>(GetTable())->ChecksumAdjustment();
+}
+
+void FontHeaderTable::Builder::SetChecksumAdjustment(int64_t adjustment) {
+  InternalWriteData()->WriteULong(Offset::kCheckSumAdjustment, adjustment);
+}
+
+int64_t FontHeaderTable::Builder::MagicNumber() {
+  return down_cast<FontHeaderTable*>(GetTable())->MagicNumber();
+}
+
+void FontHeaderTable::Builder::SetMagicNumber(int64_t magic_number) {
+  InternalWriteData()->WriteULong(Offset::kMagicNumber, magic_number);
+}
+
+int32_t FontHeaderTable::Builder::FlagsAsInt() {
+  return down_cast<FontHeaderTable*>(GetTable())->FlagsAsInt();
+}
+
+void FontHeaderTable::Builder::SetFlagsAsInt(int32_t flags) {
+  InternalWriteData()->WriteUShort(Offset::kFlags, flags);
+}
+
+int32_t FontHeaderTable::Builder::UnitsPerEm() {
+  return down_cast<FontHeaderTable*>(GetTable())->UnitsPerEm();
+}
+
+void FontHeaderTable::Builder::SetUnitsPerEm(int32_t units) {
+  InternalWriteData()->WriteUShort(Offset::kUnitsPerEm, units);
+}
+
+int64_t FontHeaderTable::Builder::Created() {
+  return down_cast<FontHeaderTable*>(GetTable())->Created();
+}
+
+void FontHeaderTable::Builder::SetCreated(int64_t date) {
+  InternalWriteData()->WriteDateTime(Offset::kCreated, date);
+}
+
+int64_t FontHeaderTable::Builder::Modified() {
+  return down_cast<FontHeaderTable*>(GetTable())->Modified();
+}
+
+void FontHeaderTable::Builder::SetModified(int64_t date) {
+  InternalWriteData()->WriteDateTime(Offset::kModified, date);
+}
+
+int32_t FontHeaderTable::Builder::XMin() {
+  return down_cast<FontHeaderTable*>(GetTable())->XMin();
+}
+
+void FontHeaderTable::Builder::SetXMin(int32_t xmin) {
+  InternalWriteData()->WriteShort(Offset::kXMin, xmin);
+}
+
+int32_t FontHeaderTable::Builder::YMin() {
+  return down_cast<FontHeaderTable*>(GetTable())->YMin();
+}
+
+void FontHeaderTable::Builder::SetYMin(int32_t ymin) {
+  InternalWriteData()->WriteShort(Offset::kYMin, ymin);
+}
+
+int32_t FontHeaderTable::Builder::XMax() {
+  return down_cast<FontHeaderTable*>(GetTable())->XMax();
+}
+
+void FontHeaderTable::Builder::SetXMax(int32_t xmax) {
+  InternalWriteData()->WriteShort(Offset::kXMax, xmax);
+}
+
+int32_t FontHeaderTable::Builder::YMax() {
+  return down_cast<FontHeaderTable*>(GetTable())->YMax();
+}
+
+void FontHeaderTable::Builder::SetYMax(int32_t ymax) {
+  InternalWriteData()->WriteShort(Offset::kYMax, ymax);
+}
+
+int32_t FontHeaderTable::Builder::MacStyleAsInt() {
+  return down_cast<FontHeaderTable*>(GetTable())->MacStyleAsInt();
+}
+
+void FontHeaderTable::Builder::SetMacStyleAsInt(int32_t style) {
+  InternalWriteData()->WriteUShort(Offset::kMacStyle, style);
+}
+
+int32_t FontHeaderTable::Builder::LowestRecPPEM() {
+  return down_cast<FontHeaderTable*>(GetTable())->LowestRecPPEM();
+}
+
+void FontHeaderTable::Builder::SetLowestRecPPEM(int32_t size) {
+  InternalWriteData()->WriteUShort(Offset::kLowestRecPPEM, size);
+}
+
+int32_t FontHeaderTable::Builder::FontDirectionHint() {
+  return down_cast<FontHeaderTable*>(GetTable())->FontDirectionHint();
+}
+
+void FontHeaderTable::Builder::SetFontDirectionHint(int32_t hint) {
+  InternalWriteData()->WriteShort(Offset::kFontDirectionHint, hint);
+}
+
+int32_t FontHeaderTable::Builder::IndexToLocFormat() {
+  return down_cast<FontHeaderTable*>(GetTable())->IndexToLocFormat();
+}
+
+void FontHeaderTable::Builder::SetIndexToLocFormat(int32_t format) {
+  InternalWriteData()->WriteShort(Offset::kIndexToLocFormat, format);
+}
+
+int32_t FontHeaderTable::Builder::GlyphDataFormat() {
+  return down_cast<FontHeaderTable*>(GetTable())->GlyphDataFormat();
+}
+
+void FontHeaderTable::Builder::SetGlyphDataFormat(int32_t format) {
+  InternalWriteData()->WriteShort(Offset::kGlyphDataFormat, format);
+}
+
+CALLER_ATTACH FontHeaderTable::Builder*
+    FontHeaderTable::Builder::CreateBuilder(Header* header,
+                                            WritableFontData* data) {
+  Ptr<FontHeaderTable::Builder> builder;
+  builder = new FontHeaderTable::Builder(header, data);
+  return builder.Detach();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/core/font_header_table.h b/cpp/src/sfntly/table/core/font_header_table.h
new file mode 100644
index 0000000..841955b
--- /dev/null
+++ b/cpp/src/sfntly/table/core/font_header_table.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_
+
+#include "sfntly/table/table.h"
+#include "sfntly/table/table_based_table_builder.h"
+
+namespace sfntly {
+
+struct IndexToLocFormat {
+  enum {
+    kShortOffset = 0,
+    kLongOffset = 1
+  };
+};
+
+struct FontDirectionHint {
+  enum {
+    kFullyMixed = 0,
+    kOnlyStrongLTR = 1,
+    kStrongLTRAndNeutral = 2,
+    kOnlyStrongRTL = -1,
+    kStrongRTLAndNeutral = -2
+  };
+};
+
+class FontHeaderTable : public Table, public RefCounted<FontHeaderTable> {
+ public:
+  class Builder : public TableBasedTableBuilder, public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+
+    virtual int32_t TableVersion();
+    virtual void SetTableVersion(int32_t version);
+    virtual int32_t FontRevision();
+    virtual void SetFontRevision(int32_t revision);
+    virtual int64_t ChecksumAdjustment();
+    virtual void SetChecksumAdjustment(int64_t adjustment);
+    virtual int64_t MagicNumber();
+    virtual void SetMagicNumber(int64_t magic_number);
+    virtual int32_t FlagsAsInt();
+    virtual void SetFlagsAsInt(int32_t flags);
+    // TODO(arthurhsu): IMPLEMENT EnumSet<Flags> Flags()
+    // TODO(arthurhsu): IMPLEMENT setFlags(EnumSet<Flags> flags)
+    virtual int32_t UnitsPerEm();
+    virtual void SetUnitsPerEm(int32_t units);
+    virtual int64_t Created();
+    virtual void SetCreated(int64_t date);
+    virtual int64_t Modified();
+    virtual void SetModified(int64_t date);
+    virtual int32_t XMin();
+    virtual void SetXMin(int32_t xmin);
+    virtual int32_t YMin();
+    virtual void SetYMin(int32_t ymin);
+    virtual int32_t XMax();
+    virtual void SetXMax(int32_t xmax);
+    virtual int32_t YMax();
+    virtual void SetYMax(int32_t ymax);
+    virtual int32_t MacStyleAsInt();
+    virtual void SetMacStyleAsInt(int32_t style);
+    // TODO(arthurhsu): IMPLEMENT EnumSet<MacStyle> macStyle()
+    // TODO(arthurhsu): IMPLEMENT setMacStyle(EnumSet<MacStyle> style)
+    virtual int32_t LowestRecPPEM();
+    virtual void SetLowestRecPPEM(int32_t size);
+    virtual int32_t FontDirectionHint();
+    virtual void SetFontDirectionHint(int32_t hint);
+    virtual int32_t IndexToLocFormat();
+    virtual void SetIndexToLocFormat(int32_t format);
+    virtual int32_t GlyphDataFormat();
+    virtual void SetGlyphDataFormat(int32_t format);
+
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+  };
+
+  virtual ~FontHeaderTable();
+  int32_t TableVersion();
+  int32_t FontRevision();
+
+  // Get the checksum adjustment. To compute: set it to 0, sum the entire font
+  // as ULONG, then store 0xB1B0AFBA - sum.
+  int64_t ChecksumAdjustment();
+
+  // Get the magic number. Set to 0x5F0F3CF5.
+  int64_t MagicNumber();
+
+  // TODO(arthurhsu): IMPLEMENT: EnumSet<Flags>
+  int32_t FlagsAsInt();
+  // TODO(arthurhsu): IMPLEMENT: Flags() returning EnumSet<Flags>
+
+  int32_t UnitsPerEm();
+
+  // Get the created date. Number of seconds since 12:00 midnight, January 1,
+  // 1904. 64-bit integer.
+  int64_t Created();
+  // Get the modified date. Number of seconds since 12:00 midnight, January 1,
+  // 1904. 64-bit integer.
+  int64_t Modified();
+
+  // Get the x min. For all glyph bounding boxes.
+  int32_t XMin();
+  // Get the y min. For all glyph bounding boxes.
+  int32_t YMin();
+  // Get the x max. For all glyph bounding boxes.
+  int32_t XMax();
+  // Get the y max. For all glyph bounding boxes.
+  int32_t YMax();
+
+  // TODO(arthurhsu): IMPLEMENT: EnumSet<MacStyle>
+  int32_t MacStyleAsInt();
+  // TODO(arthurhsu): IMPLEMENT: macStyle() returning EnumSet<MacStyle>
+
+  int32_t LowestRecPPEM();
+  int32_t FontDirectionHint();  // Note: no AsInt() form, already int
+  int32_t IndexToLocFormat();  // Note: no AsInt() form, already int
+  int32_t GlyphDataFormat();
+
+ private:
+  struct Offset {
+    enum {
+      kTableVersion = 0,
+      kFontRevision = 4,
+      kCheckSumAdjustment = 8,
+      kMagicNumber = 12,
+      kFlags = 16,
+      kUnitsPerEm = 18,
+      kCreated = 20,
+      kModified = 28,
+      kXMin = 36,
+      kYMin = 38,
+      kXMax = 40,
+      kYMax = 42,
+      kMacStyle = 44,
+      kLowestRecPPEM = 46,
+      kFontDirectionHint = 48,
+      kIndexToLocFormat = 50,
+      kGlyphDataFormat = 52
+    };
+  };
+
+  FontHeaderTable(Header* header, ReadableFontData* data);
+};
+typedef Ptr<FontHeaderTable> FontHeaderTablePtr;
+typedef Ptr<FontHeaderTable::Builder> FontHeaderTableBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_FONT_HEADER_TABLE_H_
diff --git a/cpp/src/sfntly/table/core/horizontal_device_metrics_table.cc b/cpp/src/sfntly/table/core/horizontal_device_metrics_table.cc
new file mode 100644
index 0000000..50b0cf5
--- /dev/null
+++ b/cpp/src/sfntly/table/core/horizontal_device_metrics_table.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/core/horizontal_device_metrics_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * HorizontalDeviceMetricsTable class
+ ******************************************************************************/
+HorizontalDeviceMetricsTable:: ~HorizontalDeviceMetricsTable() {}
+
+int32_t HorizontalDeviceMetricsTable::Version() {
+  return data_->ReadUShort(Offset::kVersion);
+}
+
+int32_t HorizontalDeviceMetricsTable::NumRecords() {
+  return data_->ReadShort(Offset::kNumRecords);
+}
+
+int32_t HorizontalDeviceMetricsTable::RecordSize() {
+  return data_->ReadLong(Offset::kSizeDeviceRecord);
+}
+
+int32_t HorizontalDeviceMetricsTable::PixelSize(int32_t record_index) {
+  if (record_index < 0 || record_index >= NumRecords()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException();
+#endif
+    return -1;
+  }
+  return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() +
+                          Offset::kDeviceRecordPixelSize);
+}
+
+int32_t HorizontalDeviceMetricsTable::MaxWidth(int32_t record_index) {
+  if (record_index < 0 || record_index >= NumRecords()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException();
+#endif
+    return -1;
+  }
+  return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() +
+                          Offset::kDeviceRecordMaxWidth);
+}
+
+int32_t HorizontalDeviceMetricsTable::Width(int32_t record_index,
+                                            int32_t glyph_num) {
+  if (record_index < 0 || record_index >= NumRecords() ||
+      glyph_num < 0 || glyph_num >= num_glyphs_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException();
+#endif
+    return -1;
+  }
+  return data_->ReadUByte(Offset::kRecords + record_index * RecordSize() +
+                          Offset::kDeviceRecordWidths + glyph_num);
+}
+
+HorizontalDeviceMetricsTable::HorizontalDeviceMetricsTable(
+    Header* header,
+    ReadableFontData* data,
+    int32_t num_glyphs)
+    : Table(header, data), num_glyphs_(num_glyphs) {
+}
+
+/******************************************************************************
+ * HorizontalDeviceMetricsTable::Builder class
+ ******************************************************************************/
+HorizontalDeviceMetricsTable::Builder::Builder(Header* header,
+                                               WritableFontData* data)
+    : TableBasedTableBuilder(header, data), num_glyphs_(-1) {
+}
+
+HorizontalDeviceMetricsTable::Builder::Builder(Header* header,
+                                               ReadableFontData* data)
+    : TableBasedTableBuilder(header, data), num_glyphs_(-1) {
+}
+
+HorizontalDeviceMetricsTable::Builder::~Builder() {}
+
+CALLER_ATTACH FontDataTable*
+HorizontalDeviceMetricsTable::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new HorizontalDeviceMetricsTable(header(), data,
+                                                            num_glyphs_);
+  return table.Detach();
+}
+
+void HorizontalDeviceMetricsTable::Builder::SetNumGlyphs(int32_t num_glyphs) {
+  if (num_glyphs < 0) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IllegalArgumentException("Number of glyphs can't be negative.");
+#endif
+    return;
+  }
+  num_glyphs_ = num_glyphs;
+  HorizontalDeviceMetricsTable* table =
+      down_cast<HorizontalDeviceMetricsTable*>(GetTable());
+  if (table) {
+    table->num_glyphs_ = num_glyphs;
+  }
+}
+
+CALLER_ATTACH HorizontalDeviceMetricsTable::Builder*
+HorizontalDeviceMetricsTable::Builder::CreateBuilder(Header* header,
+                                                     WritableFontData* data) {
+  Ptr<HorizontalDeviceMetricsTable::Builder> builder;
+  builder = new HorizontalDeviceMetricsTable::Builder(header, data);
+  return builder.Detach();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/core/horizontal_device_metrics_table.h b/cpp/src/sfntly/table/core/horizontal_device_metrics_table.h
new file mode 100644
index 0000000..4a27ba0
--- /dev/null
+++ b/cpp/src/sfntly/table/core/horizontal_device_metrics_table.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_
+
+#include "sfntly/table/table.h"
+#include "sfntly/table/table_based_table_builder.h"
+
+namespace sfntly {
+
+// A Horizontal Device Metrics table - 'hdmx'
+class HorizontalDeviceMetricsTable
+    : public Table,
+      public RefCounted<HorizontalDeviceMetricsTable> {
+ public:
+  class Builder : public TableBasedTableBuilder, public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+
+    void SetNumGlyphs(int32_t num_glyphs);
+
+   private:
+    int32_t num_glyphs_;
+  };
+
+  virtual ~HorizontalDeviceMetricsTable();
+
+  int32_t Version();
+  int32_t NumRecords();
+  int32_t RecordSize();
+  int32_t PixelSize(int32_t record_index);
+  int32_t MaxWidth(int32_t record_index);
+  int32_t Width(int32_t record_index, int32_t glyph_num);
+
+ private:
+  struct Offset {
+    enum {
+      kVersion = 0,

+      kNumRecords = 2,

+      kSizeDeviceRecord = 4,

+      kRecords = 8,

+

+      // Offsets within a device record

+      kDeviceRecordPixelSize = 0,

+      kDeviceRecordMaxWidth = 1,

+      kDeviceRecordWidths = 2,
+    };
+  };
+  HorizontalDeviceMetricsTable(Header* header,
+                               ReadableFontData* data,
+                               int32_t num_glyphs);
+
+  int32_t num_glyphs_;
+};
+typedef Ptr<HorizontalDeviceMetricsTable> HorizontalDeviceMetricsTablePtr;
+typedef Ptr<HorizontalDeviceMetricsTable::Builder>
+            HorizontalDeviceMetricsTableBuilderPtr;
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_DEVICE_METRICS_TABLE_H_
diff --git a/cpp/src/sfntly/table/core/horizontal_header_table.cc b/cpp/src/sfntly/table/core/horizontal_header_table.cc
new file mode 100644
index 0000000..43c2058
--- /dev/null
+++ b/cpp/src/sfntly/table/core/horizontal_header_table.cc
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/core/horizontal_header_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * HorizontalHeaderTable class
+ ******************************************************************************/
+HorizontalHeaderTable:: ~HorizontalHeaderTable() {}
+
+int32_t HorizontalHeaderTable::TableVersion() {
+  return data_->ReadFixed(Offset::kVersion);
+}
+
+int32_t HorizontalHeaderTable::Ascender() {
+  return data_->ReadShort(Offset::kAscender);
+}
+
+int32_t HorizontalHeaderTable::Descender() {
+  return data_->ReadShort(Offset::kDescender);
+}
+
+int32_t HorizontalHeaderTable::LineGap() {
+  return data_->ReadShort(Offset::kLineGap);
+}
+
+int32_t HorizontalHeaderTable::AdvanceWidthMax() {
+  return data_->ReadUShort(Offset::kAdvanceWidthMax);
+}
+
+int32_t HorizontalHeaderTable::MinLeftSideBearing() {
+  return data_->ReadShort(Offset::kMinLeftSideBearing);
+}
+
+int32_t HorizontalHeaderTable::MinRightSideBearing() {
+  return data_->ReadShort(Offset::kMinRightSideBearing);
+}
+
+int32_t HorizontalHeaderTable::XMaxExtent() {
+  return data_->ReadShort(Offset::kXMaxExtent);
+}
+
+int32_t HorizontalHeaderTable::CaretSlopeRise() {
+  return data_->ReadShort(Offset::kCaretSlopeRise);
+}
+
+int32_t HorizontalHeaderTable::CaretSlopeRun() {
+  return data_->ReadShort(Offset::kCaretSlopeRun);
+}
+
+int32_t HorizontalHeaderTable::CaretOffset() {
+  return data_->ReadShort(Offset::kCaretOffset);
+}
+
+int32_t HorizontalHeaderTable::MetricDataFormat() {
+  return data_->ReadShort(Offset::kMetricDataFormat);
+}
+
+int32_t HorizontalHeaderTable::NumberOfHMetrics() {
+  return data_->ReadUShort(Offset::kNumberOfHMetrics);
+}
+
+HorizontalHeaderTable:: HorizontalHeaderTable(Header* header,
+                                              ReadableFontData* data)
+    : Table(header, data) {
+}
+
+/******************************************************************************
+ * HorizontalHeaderTable::Builder class
+ ******************************************************************************/
+HorizontalHeaderTable::Builder::Builder(Header* header, WritableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+HorizontalHeaderTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+HorizontalHeaderTable::Builder::~Builder() {}
+
+CALLER_ATTACH FontDataTable*
+    HorizontalHeaderTable::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new HorizontalHeaderTable(header(), data);
+  return table.Detach();
+}
+
+CALLER_ATTACH HorizontalHeaderTable::Builder*
+    HorizontalHeaderTable::Builder::CreateBuilder(Header* header,
+                                                  WritableFontData* data) {
+  Ptr<HorizontalHeaderTable::Builder> builder;
+  builder = new HorizontalHeaderTable::Builder(header, data);
+  return builder.Detach();
+}
+
+int32_t HorizontalHeaderTable::Builder::TableVersion() {
+  return InternalReadData()->ReadFixed(Offset::kVersion);
+}
+
+void HorizontalHeaderTable::Builder::SetTableVersion(int32_t version) {
+  InternalWriteData()->WriteFixed(Offset::kVersion, version);
+}
+
+int32_t HorizontalHeaderTable::Builder::Ascender() {
+  return InternalReadData()->ReadShort(Offset::kAscender);
+}
+
+void HorizontalHeaderTable::Builder::SetAscender(int32_t ascender) {
+  InternalWriteData()->WriteShort(Offset::kVersion, ascender);
+}
+
+int32_t HorizontalHeaderTable::Builder::Descender() {
+  return InternalReadData()->ReadShort(Offset::kDescender);
+}
+
+void HorizontalHeaderTable::Builder::SetDescender(int32_t descender) {
+  InternalWriteData()->WriteShort(Offset::kDescender, descender);
+}
+
+int32_t HorizontalHeaderTable::Builder::LineGap() {
+  return InternalReadData()->ReadShort(Offset::kLineGap);
+}
+
+void HorizontalHeaderTable::Builder::SetLineGap(int32_t line_gap) {
+  InternalWriteData()->WriteShort(Offset::kLineGap, line_gap);
+}
+
+int32_t HorizontalHeaderTable::Builder::AdvanceWidthMax() {
+  return InternalReadData()->ReadUShort(Offset::kAdvanceWidthMax);
+}
+
+void HorizontalHeaderTable::Builder::SetAdvanceWidthMax(int32_t value) {
+  InternalWriteData()->WriteUShort(Offset::kAdvanceWidthMax, value);
+}
+
+int32_t HorizontalHeaderTable::Builder::MinLeftSideBearing() {
+  return InternalReadData()->ReadShort(Offset::kMinLeftSideBearing);
+}
+
+void HorizontalHeaderTable::Builder::SetMinLeftSideBearing(int32_t value) {
+  InternalWriteData()->WriteShort(Offset::kMinLeftSideBearing, value);
+}
+
+int32_t HorizontalHeaderTable::Builder::MinRightSideBearing() {
+  return InternalReadData()->ReadShort(Offset::kMinRightSideBearing);
+}
+
+void HorizontalHeaderTable::Builder::SetMinRightSideBearing(int32_t value) {
+  InternalWriteData()->WriteShort(Offset::kMinRightSideBearing, value);
+}
+
+int32_t HorizontalHeaderTable::Builder::XMaxExtent() {
+  return InternalReadData()->ReadShort(Offset::kXMaxExtent);
+}
+
+void HorizontalHeaderTable::Builder::SetXMaxExtent(int32_t value) {
+  InternalWriteData()->WriteShort(Offset::kXMaxExtent, value);
+}
+
+int32_t HorizontalHeaderTable::Builder::CaretSlopeRise() {
+  return InternalReadData()->ReadUShort(Offset::kCaretSlopeRise);
+}
+
+void HorizontalHeaderTable::Builder::SetCaretSlopeRise(int32_t value) {
+  InternalWriteData()->WriteUShort(Offset::kCaretSlopeRise, value);
+}
+
+int32_t HorizontalHeaderTable::Builder::CaretSlopeRun() {
+  return InternalReadData()->ReadUShort(Offset::kCaretSlopeRun);
+}
+
+void HorizontalHeaderTable::Builder::SetCaretSlopeRun(int32_t value) {
+  InternalWriteData()->WriteUShort(Offset::kCaretSlopeRun, value);
+}
+
+int32_t HorizontalHeaderTable::Builder::CaretOffset() {
+  return InternalReadData()->ReadUShort(Offset::kCaretOffset);
+}
+
+void HorizontalHeaderTable::Builder::SetCaretOffset(int32_t value) {
+  InternalWriteData()->WriteUShort(Offset::kCaretOffset, value);
+}
+
+int32_t HorizontalHeaderTable::Builder::MetricDataFormat() {
+  return InternalReadData()->ReadUShort(Offset::kMetricDataFormat);
+}
+
+void HorizontalHeaderTable::Builder::SetMetricDataFormat(int32_t value) {
+  InternalWriteData()->WriteUShort(Offset::kMetricDataFormat, value);
+}
+
+int32_t HorizontalHeaderTable::Builder::NumberOfHMetrics() {
+  return InternalReadData()->ReadUShort(Offset::kNumberOfHMetrics);
+}
+
+void HorizontalHeaderTable::Builder::SetNumberOfHMetrics(int32_t value) {
+  InternalWriteData()->WriteUShort(Offset::kNumberOfHMetrics, value);
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/core/horizontal_header_table.h b/cpp/src/sfntly/table/core/horizontal_header_table.h
new file mode 100644
index 0000000..71f30b4
--- /dev/null
+++ b/cpp/src/sfntly/table/core/horizontal_header_table.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_
+
+#include "sfntly/table/table.h"
+#include "sfntly/table/table_based_table_builder.h"
+
+namespace sfntly {
+
+// A Horizontal Header table - 'hhea'.
+class HorizontalHeaderTable : public Table,
+                              public RefCounted<HorizontalHeaderTable> {
+ public:
+  // Builder for a Horizontal Header table - 'hhea'.
+  class Builder : public TableBasedTableBuilder, public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+
+    int32_t TableVersion();
+    void SetTableVersion(int32_t version);
+    int32_t Ascender();
+    void SetAscender(int32_t ascender);
+    int32_t Descender();
+    void SetDescender(int32_t descender);
+    int32_t LineGap();
+    void SetLineGap(int32_t line_gap);
+    int32_t AdvanceWidthMax();
+    void SetAdvanceWidthMax(int32_t value);
+    int32_t MinLeftSideBearing();
+    void SetMinLeftSideBearing(int32_t value);
+    int32_t MinRightSideBearing();
+    void SetMinRightSideBearing(int32_t value);
+    int32_t XMaxExtent();
+    void SetXMaxExtent(int32_t value);
+    int32_t CaretSlopeRise();
+    void SetCaretSlopeRise(int32_t value);
+    int32_t CaretSlopeRun();
+    void SetCaretSlopeRun(int32_t value);
+    int32_t CaretOffset();
+    void SetCaretOffset(int32_t value);
+    int32_t MetricDataFormat();
+    void SetMetricDataFormat(int32_t value);
+    int32_t NumberOfHMetrics();
+    void SetNumberOfHMetrics(int32_t value);
+  };
+
+  virtual ~HorizontalHeaderTable();
+  int32_t TableVersion();
+  int32_t Ascender();
+  int32_t Descender();
+  int32_t LineGap();
+  int32_t AdvanceWidthMax();
+  int32_t MinLeftSideBearing();
+  int32_t MinRightSideBearing();
+  int32_t XMaxExtent();
+  int32_t CaretSlopeRise();
+  int32_t CaretSlopeRun();
+  int32_t CaretOffset();
+  int32_t MetricDataFormat();
+  int32_t NumberOfHMetrics();
+
+ private:
+  struct Offset {
+    enum {
+      kVersion = 0,
+      kAscender = 4,
+      kDescender = 6,
+      kLineGap = 8,
+      kAdvanceWidthMax = 10,
+      kMinLeftSideBearing = 12,
+      kMinRightSideBearing = 14,
+      kXMaxExtent = 16,
+      kCaretSlopeRise = 18,
+      kCaretSlopeRun = 20,
+      kCaretOffset = 22,
+      kMetricDataFormat = 32,
+      kNumberOfHMetrics = 34,
+    };
+  };
+
+  HorizontalHeaderTable(Header* header, ReadableFontData* data);
+};
+typedef Ptr<HorizontalHeaderTable> HorizontalHeaderTablePtr;
+typedef Ptr<HorizontalHeaderTable::Builder> HorizontalHeaderTableBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_HEADER_TABLE_H_
diff --git a/cpp/src/sfntly/table/core/horizontal_metrics_table.cc b/cpp/src/sfntly/table/core/horizontal_metrics_table.cc
new file mode 100644
index 0000000..156387d
--- /dev/null
+++ b/cpp/src/sfntly/table/core/horizontal_metrics_table.cc
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/core/horizontal_metrics_table.h"
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+/******************************************************************************
+ * HorizontalMetricsTable class
+ ******************************************************************************/
+HorizontalMetricsTable::~HorizontalMetricsTable() {}
+
+int32_t HorizontalMetricsTable::NumberOfHMetrics() {
+  return num_hmetrics_;
+}
+
+int32_t HorizontalMetricsTable::NumberOfLSBs() {
+  return num_glyphs_ - num_hmetrics_;
+}
+
+int32_t HorizontalMetricsTable::HMetricAdvanceWidth(int32_t entry) {
+  if (entry > num_hmetrics_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#endif
+    return 0;
+  }
+  int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) +
+                   Offset::kHMetricsAdvanceWidth;
+  return data_->ReadUShort(offset);
+}
+
+int32_t HorizontalMetricsTable::HMetricLSB(int32_t entry) {
+  if (entry > num_hmetrics_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#endif
+    return 0;
+  }
+  int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) +
+                   Offset::kHMetricsLeftSideBearing;
+  return data_->ReadShort(offset);
+}
+
+int32_t HorizontalMetricsTable::LsbTableEntry(int32_t entry) {
+  if (entry > num_hmetrics_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#endif
+    return 0;
+  }
+  int32_t offset = Offset::kHMetricsStart + (entry * Offset::kHMetricsSize) +
+                   Offset::kLeftSideBearingSize;
+  return data_->ReadShort(offset);
+}
+
+int32_t HorizontalMetricsTable::AdvanceWidth(int32_t glyph_id) {
+  if (glyph_id < num_hmetrics_) {
+    return HMetricAdvanceWidth(glyph_id);
+  }
+  return HMetricAdvanceWidth(glyph_id - num_hmetrics_);
+}
+
+int32_t HorizontalMetricsTable::LeftSideBearing(int32_t glyph_id) {
+  if (glyph_id < num_hmetrics_) {
+    return HMetricLSB(glyph_id);
+  }
+  return LsbTableEntry(glyph_id - num_hmetrics_);
+}
+
+HorizontalMetricsTable::HorizontalMetricsTable(Header* header,
+                                               ReadableFontData* data,
+                                               int32_t num_hmetrics,
+                                               int32_t num_glyphs)
+    : Table(header, data),
+      num_hmetrics_(num_hmetrics),
+      num_glyphs_(num_glyphs) {
+}
+
+/******************************************************************************
+ * HorizontalMetricsTable::Builder class
+ ******************************************************************************/
+HorizontalMetricsTable::Builder::Builder(Header* header, WritableFontData* data)
+    : TableBasedTableBuilder(header, data), num_hmetrics_(-1), num_glyphs_(-1) {
+}
+
+HorizontalMetricsTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : TableBasedTableBuilder(header, data), num_hmetrics_(-1), num_glyphs_(-1) {
+}
+
+HorizontalMetricsTable::Builder::~Builder() {}
+
+CALLER_ATTACH FontDataTable*
+    HorizontalMetricsTable::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table =
+      new HorizontalMetricsTable(header(), data, num_hmetrics_, num_glyphs_);
+  return table.Detach();
+}
+
+CALLER_ATTACH HorizontalMetricsTable::Builder*
+    HorizontalMetricsTable::Builder::CreateBuilder(Header* header,
+                                                   WritableFontData* data) {
+  Ptr<HorizontalMetricsTable::Builder> builder;
+  builder = new HorizontalMetricsTable::Builder(header, data);
+  return builder.Detach();
+}
+
+void HorizontalMetricsTable::Builder::SetNumberOfHMetrics(
+    int32_t num_hmetrics) {
+  assert(num_hmetrics >= 0);
+  num_hmetrics_ = num_hmetrics;
+  HorizontalMetricsTable* table =
+      down_cast<HorizontalMetricsTable*>(this->GetTable());
+  table->num_hmetrics_ = num_hmetrics;
+}
+
+void HorizontalMetricsTable::Builder::SetNumGlyphs(int32_t num_glyphs) {
+  assert(num_glyphs >= 0);
+  num_glyphs_ = num_glyphs;
+  HorizontalMetricsTable* table =
+      down_cast<HorizontalMetricsTable*>(this->GetTable());
+  table->num_glyphs_ = num_glyphs;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/core/horizontal_metrics_table.h b/cpp/src/sfntly/table/core/horizontal_metrics_table.h
new file mode 100644
index 0000000..44b51f2
--- /dev/null
+++ b/cpp/src/sfntly/table/core/horizontal_metrics_table.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_
+
+#include "sfntly/table/table.h"
+#include "sfntly/table/table_based_table_builder.h"
+
+namespace sfntly {
+
+// A Horizontal Metrics table - 'hmtx'.
+class HorizontalMetricsTable : public Table,
+                               public RefCounted<HorizontalMetricsTable> {
+ public:
+  // Builder for a Horizontal Metrics Table - 'hmtx'.
+  class Builder : public TableBasedTableBuilder, public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+
+    void SetNumberOfHMetrics(int32_t num_hmetrics);
+    void SetNumGlyphs(int32_t num_glyphs);
+
+   private:
+    int32_t num_hmetrics_;
+    int32_t num_glyphs_;
+  };
+
+  virtual ~HorizontalMetricsTable();
+  int32_t NumberOfHMetrics();
+  int32_t NumberOfLSBs();
+  int32_t HMetricAdvanceWidth(int32_t entry);
+  int32_t HMetricLSB(int32_t entry);
+  int32_t LsbTableEntry(int32_t entry);
+  int32_t AdvanceWidth(int32_t glyph_id);
+  int32_t LeftSideBearing(int32_t glyph_id);
+
+ private:
+  struct Offset {
+    enum {
+      // hMetrics
+      kHMetricsStart = 0,
+      kHMetricsSize = 4,
+
+      // Offset within an hMetric
+      kHMetricsAdvanceWidth = 0,
+      kHMetricsLeftSideBearing = 2,
+
+      kLeftSideBearingSize = 2
+    };
+  };
+
+  HorizontalMetricsTable(Header* header,
+                         ReadableFontData* data,
+                         int32_t num_hmetrics,
+                         int32_t num_glyphs);
+
+  int32_t num_hmetrics_;
+  int32_t num_glyphs_;
+};
+typedef Ptr<HorizontalMetricsTable> HorizontalMetricsTablePtr;
+typedef Ptr<HorizontalMetricsTable::Builder> HorizontalMetricsTableBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_HORIZONTAL_METRICS_TABLE_H_
diff --git a/cpp/src/sfntly/table/core/maximum_profile_table.cc b/cpp/src/sfntly/table/core/maximum_profile_table.cc
new file mode 100644
index 0000000..a8ac3bc
--- /dev/null
+++ b/cpp/src/sfntly/table/core/maximum_profile_table.cc
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/core/maximum_profile_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * MaximumProfileTable class
+ ******************************************************************************/
+MaximumProfileTable::~MaximumProfileTable() {}
+
+int32_t MaximumProfileTable::TableVersion() {
+  return data_->ReadFixed(Offset::kVersion);
+}
+
+int32_t MaximumProfileTable::NumGlyphs() {
+  return data_->ReadUShort(Offset::kNumGlyphs);
+}
+
+int32_t MaximumProfileTable::MaxPoints() {
+  return data_->ReadUShort(Offset::kMaxPoints);
+}
+
+int32_t MaximumProfileTable::MaxContours() {
+  return data_->ReadUShort(Offset::kMaxContours);
+}
+
+int32_t MaximumProfileTable::MaxCompositePoints() {
+  return data_->ReadUShort(Offset::kMaxCompositePoints);
+}
+
+int32_t MaximumProfileTable::MaxCompositeContours() {
+  return data_->ReadUShort(Offset::kMaxCompositeContours);
+}
+
+int32_t MaximumProfileTable::MaxZones() {
+  return data_->ReadUShort(Offset::kMaxZones);
+}
+
+int32_t MaximumProfileTable::MaxTwilightPoints() {
+  return data_->ReadUShort(Offset::kMaxTwilightPoints);
+}
+
+int32_t MaximumProfileTable::MaxStorage() {
+  return data_->ReadUShort(Offset::kMaxStorage);
+}
+
+int32_t MaximumProfileTable::MaxFunctionDefs() {
+  return data_->ReadUShort(Offset::kMaxFunctionDefs);
+}
+
+int32_t MaximumProfileTable::MaxStackElements() {
+  return data_->ReadUShort(Offset::kMaxStackElements);
+}
+
+int32_t MaximumProfileTable::MaxSizeOfInstructions() {
+  return data_->ReadUShort(Offset::kMaxSizeOfInstructions);
+}
+
+int32_t MaximumProfileTable::MaxComponentElements() {
+  return data_->ReadUShort(Offset::kMaxComponentElements);
+}
+
+int32_t MaximumProfileTable::MaxComponentDepth() {
+  return data_->ReadUShort(Offset::kMaxComponentDepth);
+}
+
+MaximumProfileTable::MaximumProfileTable(Header* header,
+                                         ReadableFontData* data)
+    : Table(header, data) {
+}
+
+/******************************************************************************
+ * MaximumProfileTable::Builder class
+ ******************************************************************************/
+MaximumProfileTable::Builder::Builder(Header* header, WritableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+MaximumProfileTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+MaximumProfileTable::Builder::~Builder() {}
+
+CALLER_ATTACH FontDataTable*
+    MaximumProfileTable::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new MaximumProfileTable(header(), data);
+  return table.Detach();
+}
+
+CALLER_ATTACH MaximumProfileTable::Builder*
+    MaximumProfileTable::Builder::CreateBuilder(Header* header,
+                                                WritableFontData* data) {
+  Ptr<MaximumProfileTable::Builder> builder;
+  builder = new MaximumProfileTable::Builder(header, data);
+  return builder.Detach();
+}
+
+int32_t MaximumProfileTable::Builder::TableVersion() {
+  return InternalReadData()->ReadUShort(Offset::kVersion);
+}
+
+void MaximumProfileTable::Builder::SetTableVersion(int32_t version) {
+  InternalWriteData()->WriteUShort(Offset::kVersion, version);
+}
+
+int32_t MaximumProfileTable::Builder::NumGlyphs() {
+  return InternalReadData()->ReadUShort(Offset::kNumGlyphs);
+}
+
+void MaximumProfileTable::Builder::SetNumGlyphs(int32_t num_glyphs) {
+  InternalWriteData()->WriteUShort(Offset::kNumGlyphs, num_glyphs);
+}
+
+int32_t MaximumProfileTable::Builder::MaxPoints() {
+  return InternalReadData()->ReadUShort(Offset::kMaxPoints);
+}
+
+void MaximumProfileTable::Builder::SetMaxPoints(int32_t max_points) {
+  InternalWriteData()->WriteUShort(Offset::kMaxPoints, max_points);
+}
+
+int32_t MaximumProfileTable::Builder::MaxContours() {
+  return InternalReadData()->ReadUShort(Offset::kMaxContours);
+}
+
+void MaximumProfileTable::Builder::SetMaxContours(int32_t max_contours) {
+  InternalWriteData()->WriteUShort(Offset::kMaxContours, max_contours);
+}
+
+int32_t MaximumProfileTable::Builder::MaxCompositePoints() {
+  return InternalReadData()->ReadUShort(Offset::kMaxCompositePoints);
+}
+
+void MaximumProfileTable::Builder::SetMaxCompositePoints(
+    int32_t max_composite_points) {
+  InternalWriteData()->WriteUShort(Offset::kMaxCompositePoints,
+                                   max_composite_points);
+}
+
+int32_t MaximumProfileTable::Builder::MaxCompositeContours() {
+  return InternalReadData()->ReadUShort(Offset::kMaxCompositeContours);
+}
+
+void MaximumProfileTable::Builder::SetMaxCompositeContours(
+    int32_t max_composite_contours) {
+  InternalWriteData()->WriteUShort(Offset::kMaxCompositeContours,
+      max_composite_contours);
+}
+
+int32_t MaximumProfileTable::Builder::MaxZones() {
+  return InternalReadData()->ReadUShort(Offset::kMaxZones);
+}
+
+void MaximumProfileTable::Builder::SetMaxZones(int32_t max_zones) {
+  InternalWriteData()->WriteUShort(Offset::kMaxZones, max_zones);
+}
+
+int32_t MaximumProfileTable::Builder::MaxTwilightPoints() {
+  return InternalReadData()->ReadUShort(Offset::kMaxTwilightPoints);
+}
+
+void MaximumProfileTable::Builder::SetMaxTwilightPoints(
+    int32_t max_twilight_points) {
+  InternalWriteData()->WriteUShort(Offset::kMaxTwilightPoints,
+                                   max_twilight_points);
+}
+
+int32_t MaximumProfileTable::Builder::MaxStorage() {
+  return InternalReadData()->ReadUShort(Offset::kMaxStorage);
+}
+
+void MaximumProfileTable::Builder::SetMaxStorage(int32_t max_storage) {
+  InternalWriteData()->WriteUShort(Offset::kMaxStorage, max_storage);
+}
+
+int32_t MaximumProfileTable::Builder::MaxFunctionDefs() {
+  return InternalReadData()->ReadUShort(Offset::kMaxFunctionDefs);
+}
+
+void MaximumProfileTable::Builder::SetMaxFunctionDefs(
+    int32_t max_function_defs) {
+  InternalWriteData()->WriteUShort(Offset::kMaxFunctionDefs, max_function_defs);
+}
+
+int32_t MaximumProfileTable::Builder::MaxStackElements() {
+  return InternalReadData()->ReadUShort(Offset::kMaxStackElements);
+}
+
+void MaximumProfileTable::Builder::SetMaxStackElements(
+    int32_t max_stack_elements) {
+  InternalWriteData()->WriteUShort(Offset::kMaxStackElements,
+                                   max_stack_elements);
+}
+
+int32_t MaximumProfileTable::Builder::MaxSizeOfInstructions() {
+  return InternalReadData()->ReadUShort(Offset::kMaxSizeOfInstructions);
+}
+
+void MaximumProfileTable::Builder::SetMaxSizeOfInstructions(
+    int32_t max_size_of_instructions) {
+  InternalWriteData()->WriteUShort(Offset::kMaxSizeOfInstructions,
+                                   max_size_of_instructions);
+}
+
+int32_t MaximumProfileTable::Builder::MaxComponentElements() {
+  return InternalReadData()->ReadUShort(Offset::kMaxComponentElements);
+}
+
+void MaximumProfileTable::Builder::SetMaxComponentElements(
+    int32_t max_component_elements) {
+  InternalWriteData()->WriteUShort(Offset::kMaxComponentElements,
+                                   max_component_elements);
+}
+
+int32_t MaximumProfileTable::Builder::MaxComponentDepth() {
+  return InternalReadData()->ReadUShort(Offset::kMaxComponentDepth);
+}
+
+void MaximumProfileTable::Builder::SetMaxComponentDepth(
+    int32_t max_component_depth) {
+  InternalWriteData()->WriteUShort(Offset::kMaxComponentDepth,
+                                   max_component_depth);
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/core/maximum_profile_table.h b/cpp/src/sfntly/table/core/maximum_profile_table.h
new file mode 100644
index 0000000..e7c5abb
--- /dev/null
+++ b/cpp/src/sfntly/table/core/maximum_profile_table.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/table/table.h"
+#include "sfntly/table/table_based_table_builder.h"
+
+namespace sfntly {
+
+// A Maximum Profile table - 'maxp'.
+class MaximumProfileTable : public Table,
+                            public RefCounted<MaximumProfileTable> {
+ public:
+  // Builder for a Maximum Profile table - 'maxp'.
+  class Builder : public TableBasedTableBuilder, public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+
+    int32_t TableVersion();
+    void SetTableVersion(int32_t version);
+    int32_t NumGlyphs();
+    void SetNumGlyphs(int32_t num_glyphs);
+    int32_t MaxPoints();
+    void SetMaxPoints(int32_t max_points);
+    int32_t MaxContours();
+    void SetMaxContours(int32_t max_contours);
+    int32_t MaxCompositePoints();
+    void SetMaxCompositePoints(int32_t max_composite_points);
+    int32_t MaxCompositeContours();
+    void SetMaxCompositeContours(int32_t max_composite_contours);
+    int32_t MaxZones();
+    void SetMaxZones(int32_t max_zones);
+    int32_t MaxTwilightPoints();
+    void SetMaxTwilightPoints(int32_t max_twilight_points);
+    int32_t MaxStorage();
+    void SetMaxStorage(int32_t max_storage);
+    int32_t MaxFunctionDefs();
+    void SetMaxFunctionDefs(int32_t max_function_defs);
+    int32_t MaxStackElements();
+    void SetMaxStackElements(int32_t max_stack_elements);
+    int32_t MaxSizeOfInstructions();
+    void SetMaxSizeOfInstructions(int32_t max_size_of_instructions);
+    int32_t MaxComponentElements();
+    void SetMaxComponentElements(int32_t max_component_elements);
+    int32_t MaxComponentDepth();
+    void SetMaxComponentDepth(int32_t max_component_depth);
+  };
+
+  virtual ~MaximumProfileTable();
+  int32_t TableVersion();
+  int32_t NumGlyphs();
+  int32_t MaxPoints();
+  int32_t MaxContours();
+  int32_t MaxCompositePoints();
+  int32_t MaxCompositeContours();
+  int32_t MaxZones();
+  int32_t MaxTwilightPoints();
+  int32_t MaxStorage();
+  int32_t MaxFunctionDefs();
+  int32_t MaxStackElements();
+  int32_t MaxSizeOfInstructions();
+  int32_t MaxComponentElements();
+  int32_t MaxComponentDepth();
+
+ private:
+  struct Offset {
+    enum {
+      // version 0.5 and 1.0
+      kVersion = 0,
+      kNumGlyphs = 4,
+
+      // version 1.0
+      kMaxPoints = 6,
+      kMaxContours = 8,
+      kMaxCompositePoints = 10,
+      kMaxCompositeContours = 12,
+      kMaxZones = 14,
+      kMaxTwilightPoints = 16,
+      kMaxStorage = 18,
+      kMaxFunctionDefs = 20,
+      kMaxInstructionDefs = 22,
+      kMaxStackElements = 24,
+      kMaxSizeOfInstructions = 26,
+      kMaxComponentElements = 28,
+      kMaxComponentDepth = 30,
+    };
+  };
+
+  MaximumProfileTable(Header* header, ReadableFontData* data);
+};
+typedef Ptr<MaximumProfileTable> MaximumProfileTablePtr;
+typedef Ptr<MaximumProfileTable::Builder> MaximumProfileTableBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_MAXIMUM_PROFILE_TABLE_H_
diff --git a/cpp/src/sfntly/table/core/name_table.cc b/cpp/src/sfntly/table/core/name_table.cc
new file mode 100644
index 0000000..8d2f64f
--- /dev/null
+++ b/cpp/src/sfntly/table/core/name_table.cc
@@ -0,0 +1,723 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/core/name_table.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <unicode/unistr.h>
+
+#include "sfntly/font.h"
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+/******************************************************************************
+ * NameTable::NameEntryId class
+ ******************************************************************************/
+NameTable::NameEntryId::NameEntryId()
+    : platform_id_(0),
+      encoding_id_(0),
+      language_id_(0),
+      name_id_(0) {
+}
+
+NameTable::NameEntryId::NameEntryId(int32_t platform_id,
+                                    int32_t encoding_id,
+                                    int32_t language_id,
+                                    int32_t name_id)
+    : platform_id_(platform_id),
+      encoding_id_(encoding_id),
+      language_id_(language_id),
+      name_id_(name_id) {
+}
+
+NameTable::NameEntryId::NameEntryId(const NameTable::NameEntryId& rhs) {
+  *this = rhs;
+}
+
+const NameTable::NameEntryId&
+    NameTable::NameEntryId::operator=(const NameTable::NameEntryId& rhs) const {
+  platform_id_ = rhs.platform_id_;
+  encoding_id_ = rhs.encoding_id_;
+  language_id_ = rhs.language_id_;
+  name_id_ = rhs.name_id_;
+  return *this;
+}
+
+bool NameTable::NameEntryId::operator==(const NameEntryId& rhs) const {
+  return platform_id_ == rhs.platform_id_ &&
+         encoding_id_ == rhs.encoding_id_ &&
+         language_id_ == rhs.language_id_ &&
+         name_id_ == rhs.name_id_;
+}
+
+bool NameTable::NameEntryId::operator<(const NameEntryId& rhs) const {
+  if (platform_id_ != rhs.platform_id_) return platform_id_ < rhs.platform_id_;
+  if (encoding_id_ != rhs.encoding_id_) return encoding_id_ < rhs.encoding_id_;
+  if (language_id_ != rhs.language_id_) return language_id_ < rhs.language_id_;
+  return name_id_ < rhs.name_id_;
+}
+
+/******************************************************************************
+ * NameTable::NameEntry class
+ ******************************************************************************/
+NameTable::NameEntry::NameEntry() {
+  Init(0, 0, 0, 0, NULL);
+}
+
+NameTable::NameEntry::NameEntry(const NameEntryId& name_entry_id,
+                                const ByteVector& name_bytes) {
+  Init(name_entry_id.platform_id(),
+       name_entry_id.encoding_id(),
+       name_entry_id.language_id(),
+       name_entry_id.name_id(),
+       &name_bytes);
+}
+
+NameTable::NameEntry::NameEntry(int32_t platform_id,
+                                int32_t encoding_id,
+                                int32_t language_id,
+                                int32_t name_id,
+                                const ByteVector& name_bytes) {
+  Init(platform_id, encoding_id, language_id, name_id, &name_bytes);
+}
+
+NameTable::NameEntry::~NameEntry() {}
+
+ByteVector* NameTable::NameEntry::NameAsBytes() {
+  return &name_bytes_;
+}
+
+int32_t NameTable::NameEntry::NameBytesLength() {
+  return name_bytes_.size();
+}
+
+UChar* NameTable::NameEntry::Name() {
+  return NameTable::ConvertFromNameBytes(&name_bytes_,
+                                         platform_id(),
+                                         encoding_id());
+}
+
+bool NameTable::NameEntry::operator==(const NameEntry& rhs) const {
+  return (name_entry_id_ == rhs.name_entry_id_ &&
+          name_bytes_ == rhs.name_bytes_);
+}
+
+void NameTable::NameEntry::Init(int32_t platform_id,
+                                int32_t encoding_id,
+                                int32_t language_id,
+                                int32_t name_id,
+                                const ByteVector* name_bytes) {
+  name_entry_id_ = NameEntryId(platform_id, encoding_id, language_id, name_id);
+  if (name_bytes) {
+    name_bytes_ = *name_bytes;
+  } else {
+    name_bytes_.clear();
+  }
+}
+
+/******************************************************************************
+ * NameTable::NameEntryBuilder class
+ ******************************************************************************/
+NameTable::NameEntryBuilder::NameEntryBuilder() {
+  Init(0, 0, 0, 0, NULL);
+}
+
+NameTable::NameEntryBuilder::NameEntryBuilder(const NameEntryId& name_entry_id,
+                                              const ByteVector& name_bytes) {
+  Init(name_entry_id.platform_id(),
+       name_entry_id.encoding_id(),
+       name_entry_id.language_id(),
+       name_entry_id.name_id(),
+       &name_bytes);
+}
+
+NameTable::NameEntryBuilder::NameEntryBuilder(
+    const NameEntryId& name_entry_id) {
+  Init(name_entry_id.platform_id(),
+       name_entry_id.encoding_id(),
+       name_entry_id.language_id(),
+       name_entry_id.name_id(),
+       NULL);
+}
+
+NameTable::NameEntryBuilder::NameEntryBuilder(NameEntry* b) {
+  Init(b->platform_id(),
+       b->encoding_id(),
+       b->language_id(),
+       b->name_id(),
+       b->NameAsBytes());
+}
+
+NameTable::NameEntryBuilder::~NameEntryBuilder() {}
+
+void NameTable::NameEntryBuilder::SetName(const UChar* name) {
+  if (name == NULL) {
+    name_entry_->name_bytes_.clear();
+    return;
+  }
+  NameTable::ConvertToNameBytes(name,
+                                name_entry_->platform_id(),
+                                name_entry_->encoding_id(),
+                                &name_entry_->name_bytes_);
+}
+
+void NameTable::NameEntryBuilder::SetName(const ByteVector& name_bytes) {
+  name_entry_->name_bytes_.clear();
+  std::copy(name_bytes.begin(),
+            name_bytes.end(),
+            name_entry_->name_bytes_.begin());
+}
+
+void NameTable::NameEntryBuilder::SetName(const ByteVector& name_bytes,
+                                          int32_t offset,
+                                          int32_t length) {
+  name_entry_->name_bytes_.clear();
+  std::copy(name_bytes.begin() + offset,
+            name_bytes.begin() + offset + length,
+            name_entry_->name_bytes_.begin());
+}
+
+void NameTable::NameEntryBuilder::Init(int32_t platform_id,
+                                       int32_t encoding_id,
+                                       int32_t language_id,
+                                       int32_t name_id,
+                                       const ByteVector* name_bytes) {
+  name_entry_ = new NameEntry();
+  name_entry_->Init(platform_id, encoding_id, language_id, name_id, name_bytes);
+}
+
+/******************************************************************************
+ * NameTable::NameEntryFilterInPlace class (C++ port only)
+ ******************************************************************************/
+NameTable::NameEntryFilterInPlace::NameEntryFilterInPlace(int32_t platform_id,
+                                                          int32_t encoding_id,
+                                                          int32_t language_id,
+                                                          int32_t name_id)
+    : platform_id_(platform_id),
+      encoding_id_(encoding_id),
+      language_id_(language_id),
+      name_id_(name_id) {
+}
+
+bool NameTable::NameEntryFilterInPlace::Accept(int32_t platform_id,
+                                               int32_t encoding_id,
+                                               int32_t language_id,
+                                               int32_t name_id) {
+  return (platform_id_ == platform_id &&
+          encoding_id_ == encoding_id &&
+          language_id_ == language_id &&
+          name_id_ == name_id);
+}
+
+/******************************************************************************
+ * NameTable::NameEntryIterator class
+ ******************************************************************************/
+NameTable::NameEntryIterator::NameEntryIterator(NameTable* table)
+    : RefIterator<NameEntry, NameTable>(table),
+      name_index_(0),
+      filter_(NULL) {
+}
+
+NameTable::NameEntryIterator::NameEntryIterator(NameTable* table,
+                                                NameEntryFilter* filter)
+    : RefIterator<NameEntry, NameTable>(table),
+      name_index_(0),
+      filter_(filter) {
+}
+
+bool NameTable::NameEntryIterator::HasNext() {
+  if (!filter_) {
+    if (name_index_ < container()->NameCount()) {
+      return true;
+    }
+    return false;
+  }
+  for (; name_index_ < container()->NameCount(); ++name_index_) {
+    if (filter_->Accept(container()->PlatformId(name_index_),
+                        container()->EncodingId(name_index_),
+                        container()->LanguageId(name_index_),
+                        container()->NameId(name_index_))) {
+      return true;
+    }
+  }
+  return false;
+}
+
+CALLER_ATTACH NameTable::NameEntry* NameTable::NameEntryIterator::Next() {
+  if (!HasNext())
+    return NULL;
+  return container()->GetNameEntry(name_index_++);
+}
+
+/******************************************************************************
+ * NameTable::Builder class
+ ******************************************************************************/
+NameTable::Builder::Builder(Header* header, WritableFontData* data)
+    : SubTableContainerTable::Builder(header, data) {
+}
+
+NameTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : SubTableContainerTable::Builder(header, data) {
+}
+
+CALLER_ATTACH NameTable::Builder*
+    NameTable::Builder::CreateBuilder(Header* header,
+                                      WritableFontData* data) {
+  Ptr<NameTable::Builder> builder;
+  builder = new NameTable::Builder(header, data);
+  return builder.Detach();
+}
+
+void NameTable::Builder::RevertNames() {
+  name_entry_map_.clear();
+  set_model_changed(false);
+}
+
+int32_t NameTable::Builder::BuilderCount() {
+  GetNameBuilders();  // Ensure name_entry_map_ is built.
+  return (int32_t)name_entry_map_.size();
+}
+
+bool NameTable::Builder::Has(int32_t platform_id,
+                             int32_t encoding_id,
+                             int32_t language_id,
+                             int32_t name_id) {
+  NameEntryId probe(platform_id, encoding_id, language_id, name_id);
+  GetNameBuilders();  // Ensure name_entry_map_ is built.
+  return (name_entry_map_.find(probe) != name_entry_map_.end());
+}
+
+CALLER_ATTACH NameTable::NameEntryBuilder*
+    NameTable::Builder::NameBuilder(int32_t platform_id,
+                                    int32_t encoding_id,
+                                    int32_t language_id,
+                                    int32_t name_id) {
+  NameEntryId probe(platform_id, encoding_id, language_id, name_id);
+  NameEntryBuilderMap builders;
+  GetNameBuilders();  // Ensure name_entry_map_ is built.
+  if (name_entry_map_.find(probe) != name_entry_map_.end()) {
+    return name_entry_map_[probe];
+  }
+  NameEntryBuilderPtr builder = new NameEntryBuilder(probe);
+  name_entry_map_[probe] = builder;
+  return builder.Detach();
+}
+
+bool NameTable::Builder::Remove(int32_t platform_id,
+                                int32_t encoding_id,
+                                int32_t language_id,
+                                int32_t name_id) {
+  NameEntryId probe(platform_id, encoding_id, language_id, name_id);
+  GetNameBuilders();  // Ensure name_entry_map_ is built.
+  NameEntryBuilderMap::iterator position = name_entry_map_.find(probe);
+  if (position != name_entry_map_.end()) {
+    name_entry_map_.erase(position);
+    return true;
+  }
+  return false;
+}
+
+CALLER_ATTACH FontDataTable*
+    NameTable::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new NameTable(header(), data);
+  return table.Detach();
+}
+
+void NameTable::Builder::SubDataSet() {
+  name_entry_map_.clear();
+  set_model_changed(false);
+}
+
+int32_t NameTable::Builder::SubDataSizeToSerialize() {
+  if (name_entry_map_.empty()) {
+    return 0;
+  }
+
+  int32_t size = NameTable::Offset::kNameRecordStart +
+                 name_entry_map_.size() * NameTable::Offset::kNameRecordSize;
+  for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(),
+                                     end = name_entry_map_.end();
+                                     b != end; ++b) {
+    NameEntryBuilderPtr p = b->second;
+    NameEntry* entry = p->name_entry();
+    size += entry->NameBytesLength();
+  }
+  return size;
+}
+
+bool NameTable::Builder::SubReadyToSerialize() {
+  return !name_entry_map_.empty();
+}
+
+int32_t NameTable::Builder::SubSerialize(WritableFontData* new_data) {
+  int32_t string_table_start_offset =
+      NameTable::Offset::kNameRecordStart +
+      name_entry_map_.size() * NameTable::Offset::kNameRecordSize;
+
+  // Header
+  new_data->WriteUShort(NameTable::Offset::kFormat, 0);
+  new_data->WriteUShort(NameTable::Offset::kCount, name_entry_map_.size());
+  new_data->WriteUShort(NameTable::Offset::kStringOffset,
+                        string_table_start_offset);
+  int32_t name_record_offset = NameTable::Offset::kNameRecordStart;
+  int32_t string_offset = 0;
+  // Note: we offered operator< in NameEntryId, which will be used by std::less,
+  //       and therefore our map will act like TreeMap in Java to provide
+  //       sorted key set.
+  for (NameEntryBuilderMap::iterator b = name_entry_map_.begin(),
+                                     end = name_entry_map_.end();
+                                     b != end; ++b) {
+    new_data->WriteUShort(
+        name_record_offset + NameTable::Offset::kNameRecordPlatformId,
+        b->first.platform_id());
+    new_data->WriteUShort(
+        name_record_offset + NameTable::Offset::kNameRecordEncodingId,
+        b->first.encoding_id());
+    new_data->WriteUShort(
+        name_record_offset + NameTable::Offset::kNameRecordLanguageId,
+        b->first.language_id());
+    new_data->WriteUShort(
+        name_record_offset + NameTable::Offset::kNameRecordNameId,
+        b->first.name_id());
+    NameEntry* builder_entry = b->second->name_entry();
+    new_data->WriteUShort(
+        name_record_offset + NameTable::Offset::kNameRecordStringLength,
+        builder_entry->NameBytesLength());
+    new_data->WriteUShort(
+        name_record_offset + NameTable::Offset::kNameRecordStringOffset,
+        string_offset);
+    name_record_offset += NameTable::Offset::kNameRecordSize;
+    string_offset += new_data->WriteBytes(
+        string_offset + string_table_start_offset,
+        builder_entry->NameAsBytes());
+  }
+
+  return string_offset + string_table_start_offset;
+}
+
+void NameTable::Builder::Initialize(ReadableFontData* data) {
+  if (data) {
+    NameTablePtr table = new NameTable(header(), data);
+    Ptr<NameEntryIterator> name_iter;
+    name_iter.Attach(table->Iterator());
+    while (name_iter->HasNext()) {
+      NameEntryPtr name_entry;
+      name_entry.Attach(name_iter->Next());
+      NameEntryBuilderPtr name_entry_builder = new NameEntryBuilder(name_entry);
+      NameEntry* builder_entry = name_entry_builder->name_entry();
+      NameEntryId probe = builder_entry->name_entry_id();
+      name_entry_map_[probe] = name_entry_builder;
+    }
+  }
+}
+
+NameTable::NameEntryBuilderMap* NameTable::Builder::GetNameBuilders() {
+  if (name_entry_map_.empty()) {
+    Initialize(InternalReadData());
+  }
+  set_model_changed();
+  return &name_entry_map_;
+}
+
+/******************************************************************************
+ * NameTable class
+ ******************************************************************************/
+NameTable::~NameTable() {}
+
+int32_t NameTable::Format() {
+  return data_->ReadUShort(Offset::kFormat);
+}
+
+int32_t NameTable::NameCount() {
+  return data_->ReadUShort(Offset::kCount);
+}
+
+int32_t NameTable::PlatformId(int32_t index) {
+  return data_->ReadUShort(Offset::kNameRecordPlatformId +
+                           OffsetForNameRecord(index));
+}
+
+int32_t NameTable::EncodingId(int32_t index) {
+  return data_->ReadUShort(Offset::kNameRecordEncodingId +
+                           OffsetForNameRecord(index));
+}
+
+int32_t NameTable::LanguageId(int32_t index) {
+  return data_->ReadUShort(Offset::kNameRecordLanguageId +
+                           OffsetForNameRecord(index));
+}
+
+int32_t NameTable::NameId(int32_t index) {
+  return data_->ReadUShort(Offset::kNameRecordNameId +
+                           OffsetForNameRecord(index));
+}
+
+void NameTable::NameAsBytes(int32_t index, ByteVector* b) {
+  assert(b);
+  int32_t length = NameLength(index);
+  b->clear();
+  b->resize(length);
+  if (length > 0) {
+    data_->ReadBytes(NameOffset(index), &((*b)[0]), 0, length);
+  }
+}
+
+void NameTable::NameAsBytes(int32_t platform_id,
+                            int32_t encoding_id,
+                            int32_t language_id,
+                            int32_t name_id,
+                            ByteVector* b) {
+  assert(b);
+  NameEntryPtr entry;
+  entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id));
+  if (entry) {
+    ByteVector* name = entry->NameAsBytes();
+    std::copy(name->begin(), name->end(), b->begin());
+  }
+}
+
+UChar* NameTable::Name(int32_t index) {
+  ByteVector b;
+  NameAsBytes(index, &b);
+  return ConvertFromNameBytes(&b, PlatformId(index), EncodingId(index));
+}
+
+UChar* NameTable::Name(int32_t platform_id,
+                       int32_t encoding_id,
+                       int32_t language_id,
+                       int32_t name_id) {
+  NameEntryPtr entry;
+  entry.Attach(GetNameEntry(platform_id, encoding_id, language_id, name_id));
+  if (entry) {
+    return entry->Name();
+  }
+  return NULL;
+}
+
+CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t index) {
+  ByteVector b;
+  NameAsBytes(index, &b);
+  NameEntryPtr instance = new NameEntry(PlatformId(index),
+                                        EncodingId(index),
+                                        LanguageId(index),
+                                        NameId(index), b);
+  return instance.Detach();
+}
+
+CALLER_ATTACH NameTable::NameEntry* NameTable::GetNameEntry(int32_t platform_id,
+                                                            int32_t encoding_id,
+                                                            int32_t language_id,
+                                                            int32_t name_id) {
+  NameTable::NameEntryFilterInPlace
+      filter(platform_id, encoding_id, language_id, name_id);
+  Ptr<NameTable::NameEntryIterator> name_entry_iter;
+  name_entry_iter.Attach(Iterator(&filter));
+  NameEntryPtr result;
+  if (name_entry_iter->HasNext()) {
+    result = name_entry_iter->Next();
+  }
+  return result;
+}
+
+CALLER_ATTACH NameTable::NameEntryIterator* NameTable::Iterator() {
+  Ptr<NameEntryIterator> output = new NameTable::NameEntryIterator(this);
+  return output.Detach();
+}
+
+CALLER_ATTACH
+NameTable::NameEntryIterator* NameTable::Iterator(NameEntryFilter* filter) {
+  Ptr<NameEntryIterator> output =
+      new NameTable::NameEntryIterator(this, filter);
+  return output.Detach();
+}
+
+NameTable::NameTable(Header* header, ReadableFontData* data)
+    : SubTableContainerTable(header, data) {}
+
+int32_t NameTable::StringOffset() {
+  return data_->ReadUShort(Offset::kStringOffset);
+}
+
+int32_t NameTable::OffsetForNameRecord(int32_t index) {
+  return Offset::kNameRecordStart + index * Offset::kNameRecordSize;
+}
+
+int32_t NameTable::NameLength(int32_t index) {
+  return data_->ReadUShort(Offset::kNameRecordStringLength +
+                           OffsetForNameRecord(index));
+}
+
+int32_t NameTable::NameOffset(int32_t index) {
+  return data_->ReadUShort(Offset::kNameRecordStringOffset +
+                           OffsetForNameRecord(index)) + StringOffset();
+}
+
+const char* NameTable::GetEncodingName(int32_t platform_id,
+                                       int32_t encoding_id) {
+  switch (platform_id) {
+    case PlatformId::kUnicode:
+      return "UTF-16BE";
+    case PlatformId::kMacintosh:
+      switch (encoding_id) {
+        case MacintoshEncodingId::kRoman:
+          return "MacRoman";
+        case MacintoshEncodingId::kJapanese:
+          return "Shift-JIS";
+        case MacintoshEncodingId::kChineseTraditional:
+          return "Big5";
+        case MacintoshEncodingId::kKorean:
+          return "EUC-KR";
+        case MacintoshEncodingId::kArabic:
+          return "MacArabic";
+        case MacintoshEncodingId::kHebrew:
+          return "MacHebrew";
+        case MacintoshEncodingId::kGreek:
+          return "MacGreek";
+        case MacintoshEncodingId::kRussian:
+          return "MacCyrillic";
+        case MacintoshEncodingId::kRSymbol:
+          return "MacSymbol";
+        case MacintoshEncodingId::kThai:
+          return "MacThai";
+        case MacintoshEncodingId::kChineseSimplified:
+          return "EUC-CN";
+        default:  // Note: unknown/unconfirmed cases are not ported.
+          break;
+      }
+      break;
+    case PlatformId::kISO:
+      break;
+    case PlatformId::kWindows:
+      switch (encoding_id) {
+        case WindowsEncodingId::kSymbol:
+        case WindowsEncodingId::kUnicodeUCS2:
+          return "UTF-16BE";
+        case WindowsEncodingId::kShiftJIS:
+          return "windows-933";
+        case WindowsEncodingId::kPRC:
+          return "windows-936";
+        case WindowsEncodingId::kBig5:
+          return "windows-950";
+        case WindowsEncodingId::kWansung:
+          return "windows-949";
+        case WindowsEncodingId::kJohab:
+          return "ms1361";
+        case WindowsEncodingId::kUnicodeUCS4:
+          return "UCS-4";
+      }
+      break;
+    case PlatformId::kCustom:
+      break;
+    default:
+      break;
+  }
+  return NULL;
+}
+
+UConverter* NameTable::GetCharset(int32_t platform_id, int32_t encoding_id) {
+  UErrorCode error_code = U_ZERO_ERROR;
+  UConverter* conv = ucnv_open(GetEncodingName(platform_id, encoding_id),
+                               &error_code);
+  if (U_SUCCESS(error_code)) {
+    return conv;
+  }
+
+  if (conv) {
+    ucnv_close(conv);
+  }
+  return NULL;
+}
+
+void NameTable::ConvertToNameBytes(const UChar* name,
+                                   int32_t platform_id,
+                                   int32_t encoding_id,
+                                   ByteVector* b) {
+  assert(b);
+  assert(name);
+  b->clear();
+  UConverter* cs = GetCharset(platform_id, encoding_id);
+  if (cs == NULL) {
+    return;
+  }
+
+  // Preflight to get buffer size.
+  UErrorCode error_code = U_ZERO_ERROR;
+  int32_t length = ucnv_fromUChars(cs, NULL, 0, name, -1, &error_code);
+  b->resize(length + 4);  // The longest termination "\0" is 4 bytes.
+  memset(&((*b)[0]), 0, length + 4);
+  error_code = U_ZERO_ERROR;
+  ucnv_fromUChars(cs,
+                  reinterpret_cast<char*>(&((*b)[0])),
+                  length + 4,
+                  name,
+                  -1,
+                  &error_code);
+  if (!U_SUCCESS(error_code)) {
+    b->clear();
+  }
+  ucnv_close(cs);
+}
+
+UChar* NameTable::ConvertFromNameBytes(ByteVector* name_bytes,
+                                       int32_t platform_id,
+                                       int32_t encoding_id) {
+  if (name_bytes == NULL || name_bytes->size() == 0) {
+    return NULL;
+  }
+  UConverter* cs = GetCharset(platform_id, encoding_id);
+  UErrorCode error_code = U_ZERO_ERROR;
+  if (cs == NULL) {
+    char buffer[11] = {0};
+#if defined (WIN32)
+    _itoa_s(platform_id, buffer, 16);
+#else
+    snprintf(buffer, sizeof(buffer), "%x", platform_id);
+#endif
+    UChar* result = new UChar[12];
+    memset(result, 0, sizeof(UChar) * 12);
+    cs = ucnv_open("utf-8", &error_code);
+    if (U_SUCCESS(error_code)) {
+      ucnv_toUChars(cs, result, 12, buffer, 11, &error_code);
+      ucnv_close(cs);
+      if (U_SUCCESS(error_code)) {
+        return result;
+      }
+    }
+    delete[] result;
+    return NULL;
+  }
+
+  // No preflight needed here, we will be bigger.
+  UChar* output_buffer = new UChar[name_bytes->size() + 1];
+  memset(output_buffer, 0, sizeof(UChar) * (name_bytes->size() + 1));
+  int32_t length = ucnv_toUChars(cs,
+                                 output_buffer,
+                                 name_bytes->size(),
+                                 reinterpret_cast<char*>(&((*name_bytes)[0])),
+                                 name_bytes->size(),
+                                 &error_code);
+  ucnv_close(cs);
+  if (length > 0) {
+    return output_buffer;
+  }
+
+  delete[] output_buffer;
+  return NULL;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/core/name_table.h b/cpp/src/sfntly/table/core/name_table.h
new file mode 100644
index 0000000..4eaafbb
--- /dev/null
+++ b/cpp/src/sfntly/table/core/name_table.h
@@ -0,0 +1,743 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_
+
+// Must include this before ICU to avoid stdint redefinition issue.
+#include "sfntly/port/type.h"
+
+#include <unicode/ucnv.h>
+#include <unicode/ustring.h>
+
+#include <map>
+#include <utility>
+
+#include "sfntly/port/java_iterator.h"
+#include "sfntly/table/subtable_container_table.h"
+
+namespace sfntly {
+
+// The following code implements the name table defined in TTF/OTF spec, which
+// can be found at http://www.microsoft.com/typography/otspec/name.htm.
+
+// Name IDs defined in TTF/OTF spec.
+struct NameId {
+  enum {
+    kUnknown = -1,
+    kCopyrightNotice = 0,
+    kFontFamilyName = 1,
+    kFontSubfamilyName = 2,
+    kUniqueFontIdentifier = 3,
+    kFullFontName = 4,
+    kVersionString = 5,
+    kPostscriptName = 6,
+    kTrademark = 7,
+    kManufacturerName = 8,
+    kDesigner = 9,
+    kDescription = 10,
+    kVendorURL = 11,
+    kDesignerURL = 12,
+    kLicenseDescription = 13,
+    kLicenseInfoURL = 14,
+    kReserved15 = 15,
+    kPreferredFamily = 16,
+    kPreferredSubfamily = 17,
+    kCompatibleFullName = 18,
+    kSampleText = 19,
+    kPostscriptCID = 20,
+    kWWSFamilyName = 21,
+    kWWSSubfamilyName = 22
+  };
+};
+
+// Unicode language IDs used in Name Records.
+struct UnicodeLanguageId {
+  enum {
+    kUnknown = -1,
+    kAll = 0
+  };
+};
+
+// Macintosh Language IDs (platform ID = 1)
+struct MacintoshLanguageId {
+  enum {
+    kUnknown = -1,
+    kEnglish = 0,
+    kFrench = 1,
+    kGerman = 2,
+    kItalian = 3,
+    kDutch = 4,
+    kSwedish = 5,
+    kSpanish = 6,
+    kDanish = 7,
+    kPortuguese = 8,
+    kNorwegian = 9,
+    kHebrew = 10,
+    kJapanese = 11,
+    kArabic = 12,
+    kFinnish = 13,
+    kGreek = 14,
+    kIcelandic = 15,
+    kMaltese = 16,
+    kTurkish = 17,
+    kCroatian = 18,
+    kChinese_Traditional = 19,
+    kUrdu = 20,
+    kHindi = 21,
+    kThai = 22,
+    kKorean = 23,
+    kLithuanian = 24,
+    kPolish = 25,
+    kHungarian = 26,
+    kEstonian = 27,
+    kLatvian = 28,
+    kSami = 29,
+    kFaroese = 30,
+    kFarsiPersian = 31,
+    kRussian = 32,
+    kChinese_Simplified = 33,
+    kFlemish = 34,
+    kIrishGaelic = 35,
+    kAlbanian = 36,
+    kRomanian = 37,
+    kCzech = 38,
+    kSlovak = 39,
+    kSlovenian = 40,
+    kYiddish = 41,
+    kSerbian = 42,
+    kMacedonian = 43,
+    kBulgarian = 44,
+    kUkrainian = 45,
+    kByelorussian = 46,
+    kUzbek = 47,
+    kKazakh = 48,
+    kAzerbaijani_Cyrillic = 49,
+    kAzerbaijani_Arabic = 50,
+    kArmenian = 51,
+    kGeorgian = 52,
+    kMoldavian = 53,
+    kKirghiz = 54,
+    kTajiki = 55,
+    kTurkmen = 56,
+    kMongolian_Mongolian = 57,
+    kMongolian_Cyrillic = 58,
+    kPashto = 59,
+    kKurdish = 60,
+    kKashmiri = 61,
+    kSindhi = 62,
+    kTibetan = 63,
+    kNepali = 64,
+    kSanskrit = 65,
+    kMarathi = 66,
+    kBengali = 67,
+    kAssamese = 68,
+    kGujarati = 69,
+    kPunjabi = 70,
+    kOriya = 71,
+    kMalayalam = 72,
+    kKannada = 73,
+    kTamil = 74,
+    kTelugu = 75,
+    kSinhalese = 76,
+    kBurmese = 77,
+    kKhmer = 78,
+    kLao = 79,
+    kVietnamese = 80,
+    kIndonesian = 81,
+    kTagalong = 82,
+    kMalay_Roman = 83,
+    kMalay_Arabic = 84,
+    kAmharic = 85,
+    kTigrinya = 86,
+    kGalla = 87,
+    kSomali = 88,
+    kSwahili = 89,
+    kKinyarwandaRuanda = 90,
+    kRundi = 91,
+    kNyanjaChewa = 92,
+    kMalagasy = 93,
+    kEsperanto = 94,
+    kWelsh = 128,
+    kBasque = 129,
+    kCatalan = 130,
+    kLatin = 131,
+    kQuenchua = 132,
+    kGuarani = 133,
+    kAymara = 134,
+    kTatar = 135,
+    kUighur = 136,
+    kDzongkha = 137,
+    kJavanese_Roman = 138,
+    kSundanese_Roman = 139,
+    kGalician = 140,
+    kAfrikaans = 141,
+    kBreton = 142,
+    kInuktitut = 143,
+    kScottishGaelic = 144,
+    kManxGaelic = 145,
+    kIrishGaelic_WithDotAbove = 146,
+    kTongan = 147,
+    kGreek_Polytonic = 148,
+    kGreenlandic = 149,
+    kAzerbaijani_Roman = 150
+  };
+};
+
+// Windows Language IDs (platformID = 3)
+struct WindowsLanguageId {
+  enum {
+    kUnknown = -1,
+    kAfrikaans_SouthAfrica = 0x0436,
+    kAlbanian_Albania = 0x041C,
+    kAlsatian_France = 0x0484,
+    kAmharic_Ethiopia = 0x045E,
+    kArabic_Algeria = 0x1401,
+    kArabic_Bahrain = 0x3C01,
+    kArabic_Egypt = 0x0C01,
+    kArabic_Iraq = 0x0801,
+    kArabic_Jordan = 0x2C01,
+    kArabic_Kuwait = 0x3401,
+    kArabic_Lebanon = 0x3001,
+    kArabic_Libya = 0x1001,
+    kArabic_Morocco = 0x1801,
+    kArabic_Oman = 0x2001,
+    kArabic_Qatar = 0x4001,
+    kArabic_SaudiArabia = 0x0401,
+    kArabic_Syria = 0x2801,
+    kArabic_Tunisia = 0x1C01,
+    kArabic_UAE = 0x3801,
+    kArabic_Yemen = 0x2401,
+    kArmenian_Armenia = 0x042B,
+    kAssamese_India = 0x044D,
+    kAzeri_Cyrillic_Azerbaijan = 0x082C,
+    kAzeri_Latin_Azerbaijan = 0x042C,
+    kBashkir_Russia = 0x046D,
+    kBasque_Basque = 0x042D,
+    kBelarusian_Belarus = 0x0423,
+    kBengali_Bangladesh = 0x0845,
+    kBengali_India = 0x0445,
+    kBosnian_Cyrillic_BosniaAndHerzegovina = 0x201A,
+    kBosnian_Latin_BosniaAndHerzegovina = 0x141A,
+    kBreton_France = 0x047E,
+    kBulgarian_Bulgaria = 0x0402,
+    kCatalan_Catalan = 0x0403,
+    kChinese_HongKongSAR = 0x0C04,
+    kChinese_MacaoSAR = 0x1404,
+    kChinese_PeoplesRepublicOfChina = 0x0804,
+    kChinese_Singapore = 0x1004,
+    kChinese_Taiwan = 0x0404,
+    kCorsican_France = 0x0483,
+    kCroatian_Croatia = 0x041A,
+    kCroatian_Latin_BosniaAndHerzegovina = 0x101A,
+    kCzech_CzechRepublic = 0x0405,
+    kDanish_Denmark = 0x0406,
+    kDari_Afghanistan = 0x048C,
+    kDivehi_Maldives = 0x0465,
+    kDutch_Belgium = 0x0813,
+    kDutch_Netherlands = 0x0413,
+    kEnglish_Australia = 0x0C09,
+    kEnglish_Belize = 0x2809,
+    kEnglish_Canada = 0x1009,
+    kEnglish_Caribbean = 0x2409,
+    kEnglish_India = 0x4009,
+    kEnglish_Ireland = 0x1809,
+    kEnglish_Jamaica = 0x2009,
+    kEnglish_Malaysia = 0x4409,
+    kEnglish_NewZealand = 0x1409,
+    kEnglish_RepublicOfThePhilippines = 0x3409,
+    kEnglish_Singapore = 0x4809,
+    kEnglish_SouthAfrica = 0x1C09,
+    kEnglish_TrinidadAndTobago = 0x2C09,
+    kEnglish_UnitedKingdom = 0x0809,
+    kEnglish_UnitedStates = 0x0409,
+    kEnglish_Zimbabwe = 0x3009,
+    kEstonian_Estonia = 0x0425,
+    kFaroese_FaroeIslands = 0x0438,
+    kFilipino_Philippines = 0x0464,
+    kFinnish_Finland = 0x040B,
+    kFrench_Belgium = 0x080C,
+    kFrench_Canada = 0x0C0C,
+    kFrench_France = 0x040C,
+    kFrench_Luxembourg = 0x140c,
+    kFrench_PrincipalityOfMonoco = 0x180C,
+    kFrench_Switzerland = 0x100C,
+    kFrisian_Netherlands = 0x0462,
+    kGalician_Galician = 0x0456,
+    kGeorgian_Georgia = 0x0437,
+    kGerman_Austria = 0x0C07,
+    kGerman_Germany = 0x0407,
+    kGerman_Liechtenstein = 0x1407,
+    kGerman_Luxembourg = 0x1007,
+    kGerman_Switzerland = 0x0807,
+    kGreek_Greece = 0x0408,
+    kGreenlandic_Greenland = 0x046F,
+    kGujarati_India = 0x0447,
+    kHausa_Latin_Nigeria = 0x0468,
+    kHebrew_Israel = 0x040D,
+    kHindi_India = 0x0439,
+    kHungarian_Hungary = 0x040E,
+    kIcelandic_Iceland = 0x040F,
+    kIgbo_Nigeria = 0x0470,
+    kIndonesian_Indonesia = 0x0421,
+    kInuktitut_Canada = 0x045D,
+    kInuktitut_Latin_Canada = 0x085D,
+    kIrish_Ireland = 0x083C,
+    kisiXhosa_SouthAfrica = 0x0434,
+    kisiZulu_SouthAfrica = 0x0435,
+    kItalian_Italy = 0x0410,
+    kItalian_Switzerland = 0x0810,
+    kJapanese_Japan = 0x0411,
+    kKannada_India = 0x044B,
+    kKazakh_Kazakhstan = 0x043F,
+    kKhmer_Cambodia = 0x0453,
+    kKiche_Guatemala = 0x0486,
+    kKinyarwanda_Rwanda = 0x0487,
+    kKiswahili_Kenya = 0x0441,
+    kKonkani_India = 0x0457,
+    kKorean_Korea = 0x0412,
+    kKyrgyz_Kyrgyzstan = 0x0440,
+    kLao_LaoPDR = 0x0454,
+    kLatvian_Latvia = 0x0426,
+    kLithuanian_Lithuania = 0x0427,
+    kLowerSorbian_Germany = 0x082E,
+    kLuxembourgish_Luxembourg = 0x046E,
+    kMacedonian_FYROM_FormerYugoslavRepublicOfMacedonia = 0x042F,
+    kMalay_BruneiDarussalam = 0x083E,
+    kMalay_Malaysia = 0x043E,
+    kMalayalam_India = 0x044C,
+    kMaltese_Malta = 0x043A,
+    kMaori_NewZealand = 0x0481,
+    kMapudungun_Chile = 0x047A,
+    kMarathi_India = 0x044E,
+    kMohawk_Mohawk = 0x047C,
+    kMongolian_Cyrillic_Mongolia = 0x0450,
+    kMongolian_Traditional_PeoplesRepublicOfChina = 0x0850,
+    kNepali_Nepal = 0x0461,
+    kNorwegian_Bokmal_Norway = 0x0414,
+    kNorwegian_Nynorsk_Norway = 0x0814,
+    kOccitan_France = 0x0482,
+    kOriya_India = 0x0448,
+    kPashto_Afghanistan = 0x0463,
+    kPolish_Poland = 0x0415,
+    kPortuguese_Brazil = 0x0416,
+    kPortuguese_Portugal = 0x0816,
+    kPunjabi_India = 0x0446,
+    kQuechua_Bolivia = 0x046B,
+    kQuechua_Ecuador = 0x086B,
+    kQuechua_Peru = 0x0C6B,
+    kRomanian_Romania = 0x0418,
+    kRomansh_Switzerland = 0x0417,
+    kRussian_Russia = 0x0419,
+    kSami_Inari_Finland = 0x243B,
+    kSami_Lule_Norway = 0x103B,
+    kSami_Lule_Sweden = 0x143B,
+    kSami_Northern_Finland = 0x0C3B,
+    kSami_Northern_Norway = 0x043B,
+    kSami_Northern_Sweden = 0x083B,
+    kSami_Skolt_Finland = 0x203B,
+    kSami_Southern_Norway = 0x183B,
+    kSami_Southern_Sweden = 0x1C3B,
+    kSanskrit_India = 0x044F,
+    kSerbian_Cyrillic_BosniaAndHerzegovina = 0x1C1A,
+    kSerbian_Cyrillic_Serbia = 0x0C1A,
+    kSerbian_Latin_BosniaAndHerzegovina = 0x181A,
+    kSerbian_Latin_Serbia = 0x081A,
+    kSesothoSaLeboa_SouthAfrica = 0x046C,
+    kSetswana_SouthAfrica = 0x0432,
+    kSinhala_SriLanka = 0x045B,
+    kSlovak_Slovakia = 0x041B,
+    kSlovenian_Slovenia = 0x0424,
+    kSpanish_Argentina = 0x2C0A,
+    kSpanish_Bolivia = 0x400A,
+    kSpanish_Chile = 0x340A,
+    kSpanish_Colombia = 0x240A,
+    kSpanish_CostaRica = 0x140A,
+    kSpanish_DominicanRepublic = 0x1C0A,
+    kSpanish_Ecuador = 0x300A,
+    kSpanish_ElSalvador = 0x440A,
+    kSpanish_Guatemala = 0x100A,
+    kSpanish_Honduras = 0x480A,
+    kSpanish_Mexico = 0x080A,
+    kSpanish_Nicaragua = 0x4C0A,
+    kSpanish_Panama = 0x180A,
+    kSpanish_Paraguay = 0x3C0A,
+    kSpanish_Peru = 0x280A,
+    kSpanish_PuertoRico = 0x500A,
+    kSpanish_ModernSort_Spain = 0x0C0A,
+    kSpanish_TraditionalSort_Spain = 0x040A,
+    kSpanish_UnitedStates = 0x540A,
+    kSpanish_Uruguay = 0x380A,
+    kSpanish_Venezuela = 0x200A,
+    kSweden_Finland = 0x081D,
+    kSwedish_Sweden = 0x041D,
+    kSyriac_Syria = 0x045A,
+    kTajik_Cyrillic_Tajikistan = 0x0428,
+    kTamazight_Latin_Algeria = 0x085F,
+    kTamil_India = 0x0449,
+    kTatar_Russia = 0x0444,
+    kTelugu_India = 0x044A,
+    kThai_Thailand = 0x041E,
+    kTibetan_PRC = 0x0451,
+    kTurkish_Turkey = 0x041F,
+    kTurkmen_Turkmenistan = 0x0442,
+    kUighur_PRC = 0x0480,
+    kUkrainian_Ukraine = 0x0422,
+    kUpperSorbian_Germany = 0x042E,
+    kUrdu_IslamicRepublicOfPakistan = 0x0420,
+    kUzbek_Cyrillic_Uzbekistan = 0x0843,
+    kUzbek_Latin_Uzbekistan = 0x0443,
+    kVietnamese_Vietnam = 0x042A,
+    kWelsh_UnitedKingdom = 0x0452,
+    kWolof_Senegal = 0x0448,
+    kYakut_Russia = 0x0485,
+    kYi_PRC = 0x0478,
+    kYoruba_Nigeria = 0x046A
+  };
+};
+
+class NameTable : public SubTableContainerTable, public RefCounted<NameTable> {
+ public:
+  // Unique identifier for a given name record.
+  class NameEntryId {
+   public:
+    NameEntryId();  // C++ port only, must provide default constructor.
+    NameEntryId(int32_t platform_id, int32_t encoding_id, int32_t language_id,
+                int32_t name_id);
+    NameEntryId(const NameEntryId&);
+    // Make gcc -Wnon-virtual-dtor happy.
+    virtual ~NameEntryId() {}
+
+    int32_t platform_id() const { return platform_id_; }
+    int32_t encoding_id() const { return encoding_id_; }
+    int32_t language_id() const { return language_id_; }
+    int32_t name_id() const { return name_id_; }
+
+    const NameEntryId& operator=(const NameEntryId& rhs) const;
+    bool operator==(const NameEntryId& rhs) const;
+    bool operator<(const NameEntryId& rhs) const;
+
+    // UNIMPLEMENTED: int hashCode()
+    //                String toString()
+
+   private:
+    mutable int32_t platform_id_;
+    mutable int32_t encoding_id_;
+    mutable int32_t language_id_;
+    mutable int32_t name_id_;
+  };
+
+  class NameEntryBuilder;
+
+  // Class to represent a name entry in the name table.
+  class NameEntry : public RefCounted<NameEntry> {
+   public:
+    NameEntry();
+    NameEntry(const NameEntryId& name_entry_id, const ByteVector& name_bytes);
+    NameEntry(int32_t platform_id,
+              int32_t encoding_id,
+              int32_t language_id,
+              int32_t name_id,
+              const ByteVector& name_bytes);
+    virtual ~NameEntry();
+
+    NameEntryId& name_entry_id() { return name_entry_id_; }
+    int32_t platform_id() const { return name_entry_id_.platform_id(); }
+    int32_t encoding_id() const { return name_entry_id_.encoding_id(); }
+    int32_t language_id() const { return name_entry_id_.language_id(); }
+    int32_t name_id() const { return name_entry_id_.name_id(); }
+
+    // Get the bytes for name.  Returned pointer is the address of private
+    // member of this class, do not attempt to delete.
+    ByteVector* NameAsBytes();
+
+    // C++ port only: get the length of NameAsBytes.
+    int32_t NameBytesLength();
+
+    // Returns the name in Unicode as UChar array.
+    // Note: ICU UChar* convention requires caller to delete[] it.
+    UChar* Name();
+    bool operator==(const NameEntry& rhs) const;
+
+    // UNIMPLEMENTED: String toString()
+    //                int hashCode()
+
+   private:
+    void Init(int32_t platform_id, int32_t encoding_id, int32_t language_id,
+              int32_t name_id, const ByteVector* name_bytes);
+
+    NameEntryId name_entry_id_;
+    ByteVector name_bytes_;
+
+    friend class NameEntryBuilder;
+  };
+
+  // Builder of a name entry.
+  // C++ port: original Java hierarchy inherits from NameEntry.  In C++ port, we
+  // opted not doing so to avoid ref count issues and nasty protected members.
+  class NameEntryBuilder : public RefCounted<NameEntryBuilder> {
+   public:
+    NameEntryBuilder();
+    NameEntryBuilder(const NameEntryId& name_entry_id,
+                     const ByteVector& name_bytes);
+    explicit NameEntryBuilder(const NameEntryId& name_entry_id);
+    explicit NameEntryBuilder(NameEntry* entry);
+    virtual ~NameEntryBuilder();
+
+    virtual void SetName(const UChar* name);
+    virtual void SetName(const ByteVector& name_bytes);
+    virtual void SetName(const ByteVector& name_bytes,
+                         int32_t offset,
+                         int32_t length);
+
+    // C++ port only. CALLER_ATTACH is not added because the lifetime shall be
+    // controlled by this class, therefore the caller shall not increase the ref
+    // count.
+    NameEntry* name_entry() { return name_entry_; }
+
+   private:
+    void Init(int32_t platform_id, int32_t encoding_id, int32_t language_id,
+              int32_t name_id, const ByteVector* name_bytes);
+
+    Ptr<NameEntry> name_entry_;
+  };
+  typedef std::map<NameEntryId, Ptr<NameEntryBuilder> > NameEntryBuilderMap;
+
+  // An interface for a filter to use with the name entry iterator. This allows
+  // name entries to be iterated and only those acceptable to the filter will be
+  // returned.
+  class NameEntryFilter {
+   public:
+    virtual bool Accept(int32_t platform_id,
+                        int32_t encoding_id,
+                        int32_t language_id,
+                        int32_t name_id) = 0;
+    // Make gcc -Wnon-virtual-dtor happy.
+    virtual ~NameEntryFilter() {}
+  };
+
+  // C++ port only: an in-place filter to mimic Java Iterator's filtering.
+  class NameEntryFilterInPlace : public NameEntryFilter {
+   public:
+    NameEntryFilterInPlace(int32_t platform_id,
+                           int32_t encoding_id,
+                           int32_t language_id,
+                           int32_t name_id);
+    // Make gcc -Wnon-virtual-dtor happy.
+    virtual ~NameEntryFilterInPlace() {}
+
+    virtual bool Accept(int32_t platform_id,
+                        int32_t encoding_id,
+                        int32_t language_id,
+                        int32_t name_id);
+
+   private:
+    int32_t platform_id_;
+    int32_t encoding_id_;
+    int32_t language_id_;
+    int32_t name_id_;
+  };
+
+  class NameEntryIterator : public RefIterator<NameEntry, NameTable> {
+   public:
+    // If filter is NULL, filter through all tables.
+    explicit NameEntryIterator(NameTable* table);
+    NameEntryIterator(NameTable* table, NameEntryFilter* filter);
+    virtual ~NameEntryIterator() {}
+
+    virtual bool HasNext();
+    virtual CALLER_ATTACH NameEntry* Next();
+
+   private:
+    int32_t name_index_;
+    NameEntryFilter* filter_;
+  };
+
+  // The builder to construct name table for outputting.
+  class Builder : public SubTableContainerTable::Builder,
+                  public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public because C++ does not allow base
+    // class to instantiate derived class with protected constructors.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+
+    // Revert the name builders for the name table to the last version that came
+    // from data.
+    void RevertNames();
+
+    // Number of name entry builders contained.
+    int32_t BuilderCount();
+
+    // Note: For C++ port, clear() is not implemented.  The clear() function
+    //       implies completely remove name entry builders, which is easy in
+    //       Java but will take a lot of efforts in C++ to release the builders
+    //       nicely and correctly.
+    // TODO(arthurhsu): IMPLEMENT
+    // Clear the name builders for the name table.
+    // void clear();
+
+    // Check the existance of a name entry builder by key.
+    bool Has(int32_t platform_id, int32_t encoding_id, int32_t language_id,
+             int32_t name_id);
+
+    // Get name entry builder by key.
+    CALLER_ATTACH NameEntryBuilder* NameBuilder(int32_t platform_id,
+        int32_t encoding_id, int32_t language_id, int32_t name_id);
+
+    // Remove name entry builder by key.
+    bool Remove(int32_t platform_id, int32_t encoding_id, int32_t language_id,
+                int32_t name_id);
+
+    // FontDataTable::Builder API implementation
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+   private:
+    void Initialize(ReadableFontData* data);
+    NameEntryBuilderMap* GetNameBuilders();
+
+    // Note: callers should use the getter funtion provided above to ensure that
+    // this is lazily initialized instead of accessing directly.
+    NameEntryBuilderMap name_entry_map_;
+  };
+
+  /****************************************************************************
+   * public methods of NameTable class
+   ****************************************************************************/
+  virtual ~NameTable();
+
+  // Get the format used in the name table.
+  virtual int32_t Format();
+
+  // Get the number of names in the name table.
+  virtual int32_t NameCount();
+
+  // Get the platform id for the given name record.
+  virtual int32_t PlatformId(int32_t index);
+
+  // Get the encoding id for the given name record.
+  // see MacintoshEncodingId, WindowsEncodingId, UnicodeEncodingId
+  virtual int32_t EncodingId(int32_t index);
+
+  // Get the language id for the given name record.
+  virtual int32_t LanguageId(int32_t index);
+
+  // Get the name id for given name record.
+  virtual int32_t NameId(int32_t index);
+
+  // Get the name as bytes for the specified name. If there is no entry for the
+  // requested name, then empty vector is returned.
+  virtual void NameAsBytes(int32_t index, ByteVector* b);
+  virtual void NameAsBytes(int32_t platform_id, int32_t encoding_id,
+                           int32_t language_id, int32_t name_id,
+                           ByteVector* b);
+
+  // Get the name as a UChar* for the given name record. If there is no
+  // encoding conversion available for the name record then a best attempt
+  // UChar* will be returned.
+  // Note: ICU UChar* convention requires caller to delete[] it.
+  virtual UChar* Name(int32_t index);
+
+  // Get the name as a UChar* for the specified name. If there is no entry for
+  // the requested name then NULL is returned. If there is no encoding
+  // conversion available for the name then a best attempt UChar* will be
+  // returned.
+  // Note: ICU UChar* convention requires caller to delete[] it.
+  virtual UChar* Name(int32_t platform_id, int32_t encoding_id,
+                      int32_t language_id, int32_t name_id);
+
+  // Note: These functions are renamed in C++ port.  Their original Java name is
+  // nameEntry().
+  virtual CALLER_ATTACH NameEntry* GetNameEntry(int32_t index);
+  virtual CALLER_ATTACH NameEntry* GetNameEntry(int32_t platform_id,
+      int32_t encoding_id, int32_t language_id, int32_t name_id);
+
+  // Note: Not implemented in C++ port due to complexity and low usage.
+  // virtual void names(std::set<NameEntryPtr>*);
+
+  // Get the iterator to iterate through all name entries.
+  virtual CALLER_ATTACH NameEntryIterator* Iterator();
+  virtual CALLER_ATTACH NameEntryIterator* Iterator(NameEntryFilter* filter);
+
+ private:
+  struct Offset {
+    enum {
+      kFormat = 0,
+      kCount = 2,
+      kStringOffset = 4,
+      kNameRecordStart = 6,
+
+      // Format 1 - offset from the end of the name records
+      kLangTagCount = 0,
+      kLangTagRecord = 2,
+
+      kNameRecordSize = 12,
+      // Name Records
+      kNameRecordPlatformId = 0,
+      kNameRecordEncodingId = 2,
+      kNameRecordLanguageId = 4,
+      kNameRecordNameId = 6,
+      kNameRecordStringLength = 8,
+      kNameRecordStringOffset = 10
+    };
+  };
+
+  // The table shall be constructed using Builder, no direct instantiation.
+  NameTable(Header* header, ReadableFontData* data);
+
+  // Get the offset to the string data in the name table.
+  int32_t StringOffset();
+
+  // Get the offset for the given name record.
+  int32_t OffsetForNameRecord(int32_t index);
+
+  // Get the length of the string data for the given name record.
+  int32_t NameLength(int32_t index);
+
+  // Get the offset of the string data for the given name record.
+  int32_t NameOffset(int32_t index);
+
+  // Note: string literals are returned.  Caller shall not attempt to manipulate
+  // the returned pointer.
+  static const char* GetEncodingName(int32_t platform_id, int32_t encoding_id);
+
+  // Note: ICU UConverter* convention requires caller to ucnv_close() it.
+  static UConverter* GetCharset(int32_t platform_id, int32_t encoding_id);
+
+  // Note: Output will be stored in ByteVector* b.  Original data in b will be
+  // erased and replaced with converted name bytes.
+  static void ConvertToNameBytes(const UChar* name, int32_t platform_id,
+                                 int32_t encoding_id, ByteVector* b);
+
+  // Note: ICU UChar* convention requires caller to delete[] it.
+  static UChar* ConvertFromNameBytes(ByteVector* name_bytes,
+                                     int32_t platform_id, int32_t encoding_id);
+};  // class NameTable
+typedef Ptr<NameTable> NameTablePtr;
+typedef Ptr<NameTable::NameEntry> NameEntryPtr;
+typedef Ptr<NameTable::Builder> NameTableBuilderPtr;
+typedef Ptr<NameTable::NameEntryBuilder> NameEntryBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_NAME_TABLE_H_
diff --git a/cpp/src/sfntly/table/core/os2_table.cc b/cpp/src/sfntly/table/core/os2_table.cc
new file mode 100644
index 0000000..7ca9d9a
--- /dev/null
+++ b/cpp/src/sfntly/table/core/os2_table.cc
@@ -0,0 +1,608 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/core/os2_table.h"
+
+namespace sfntly {
+/******************************************************************************
+ * Constants
+ ******************************************************************************/
+const int64_t CodePageRange::kLatin1_1252 = (int64_t)1 << 0;
+const int64_t CodePageRange::kLatin2_1250 = (int64_t)1 << (int64_t)1;
+const int64_t CodePageRange::kCyrillic_1251 = (int64_t)1 << 2;
+const int64_t CodePageRange::kGreek_1253 = (int64_t)1 << 3;
+const int64_t CodePageRange::kTurkish_1254 = (int64_t)1 << 4;
+const int64_t CodePageRange::kHebrew_1255 = (int64_t)1 << 5;
+const int64_t CodePageRange::kArabic_1256 = (int64_t)1 << 6;
+const int64_t CodePageRange::kWindowsBaltic_1257 = (int64_t)1 << 7;
+const int64_t CodePageRange::kVietnamese_1258 = (int64_t)1 << 8;
+const int64_t CodePageRange::kAlternateANSI9 = (int64_t)1 << 9;
+const int64_t CodePageRange::kAlternateANSI10 = (int64_t)1 << 10;
+const int64_t CodePageRange::kAlternateANSI11 = (int64_t)1 << 11;
+const int64_t CodePageRange::kAlternateANSI12 = (int64_t)1 << 12;
+const int64_t CodePageRange::kAlternateANSI13 = (int64_t)1 << 13;
+const int64_t CodePageRange::kAlternateANSI14 = (int64_t)1 << 14;
+const int64_t CodePageRange::kAlternateANSI15 = (int64_t)1 << 15;
+const int64_t CodePageRange::kThai_874 = (int64_t)1 << 16;
+const int64_t CodePageRange::kJapanJIS_932 = (int64_t)1 << 17;
+const int64_t CodePageRange::kChineseSimplified_936 = (int64_t)1 << 18;
+const int64_t CodePageRange::kKoreanWansung_949 = (int64_t)1 << 19;
+const int64_t CodePageRange::kChineseTraditional_950 = (int64_t)1 << 20;
+const int64_t CodePageRange::kKoreanJohab_1361 = (int64_t)1 << 21;
+const int64_t CodePageRange::kAlternateANSI22 = (int64_t)1 << 22;
+const int64_t CodePageRange::kAlternateANSI23 = (int64_t)1 << 23;
+const int64_t CodePageRange::kAlternateANSI24 = (int64_t)1 << 24;
+const int64_t CodePageRange::kAlternateANSI25 = (int64_t)1 << 25;
+const int64_t CodePageRange::kAlternateANSI26 = (int64_t)1 << 26;
+const int64_t CodePageRange::kAlternateANSI27 = (int64_t)1 << 27;
+const int64_t CodePageRange::kAlternateANSI28 = (int64_t)1 << 28;
+const int64_t CodePageRange::kMacintoshCharacterSet = (int64_t)1 << 29;
+const int64_t CodePageRange::kOEMCharacterSet = (int64_t)1 << 30;
+const int64_t CodePageRange::kSymbolCharacterSet = (int64_t)1 << 31;
+const int64_t CodePageRange::kReservedForOEM32 = (int64_t)1 << 32;
+const int64_t CodePageRange::kReservedForOEM33 = (int64_t)1 << 33;
+const int64_t CodePageRange::kReservedForOEM34 = (int64_t)1 << 34;
+const int64_t CodePageRange::kReservedForOEM35 = (int64_t)1 << 35;
+const int64_t CodePageRange::kReservedForOEM36 = (int64_t)1 << 36;
+const int64_t CodePageRange::kReservedForOEM37 = (int64_t)1 << 37;
+const int64_t CodePageRange::kReservedForOEM38 = (int64_t)1 << 38;
+const int64_t CodePageRange::kReservedForOEM39 = (int64_t)1 << 39;
+const int64_t CodePageRange::kReservedForOEM40 = (int64_t)1 << 40;
+const int64_t CodePageRange::kReservedForOEM41 = (int64_t)1 << 41;
+const int64_t CodePageRange::kReservedForOEM42 = (int64_t)1 << 42;
+const int64_t CodePageRange::kReservedForOEM43 = (int64_t)1 << 43;
+const int64_t CodePageRange::kReservedForOEM44 = (int64_t)1 << 44;
+const int64_t CodePageRange::kReservedForOEM45 = (int64_t)1 << 45;
+const int64_t CodePageRange::kReservedForOEM46 = (int64_t)1 << 46;
+const int64_t CodePageRange::kReservedForOEM47 = (int64_t)1 << 47;
+const int64_t CodePageRange::kIBMGreek_869 = (int64_t)1 << 48;
+const int64_t CodePageRange::kMSDOSRussion_866 = (int64_t)1 << 49;
+const int64_t CodePageRange::kMSDOSNordic_865 = (int64_t)1 << 50;
+const int64_t CodePageRange::kArabic_864 = (int64_t)1 << 51;
+const int64_t CodePageRange::kMSDOSCanadianFrench_863 = (int64_t)1 << 52;
+const int64_t CodePageRange::kHebrew_862 = (int64_t)1 << 53;
+const int64_t CodePageRange::kMSDOSIcelandic_861 = (int64_t)1 << 54;
+const int64_t CodePageRange::kMSDOSPortugese_860 = (int64_t)1 << 55;
+const int64_t CodePageRange::kIBMTurkish_857 = (int64_t)1 << 56;
+const int64_t CodePageRange::kIBMCyrillic_855 = (int64_t)1 << 57;
+const int64_t CodePageRange::kLatin2_852 = (int64_t)1 << 58;
+const int64_t CodePageRange::kMSDOSBaltic_775 = (int64_t)1 << 59;
+const int64_t CodePageRange::kGreek_737 = (int64_t)1 << 60;
+const int64_t CodePageRange::kArabic_708 = (int64_t)1 << 61;
+const int64_t CodePageRange::kLatin1_850 = (int64_t)1 << 62;
+const int64_t CodePageRange::kUS_437 = (int64_t)1 << 63;
+
+/******************************************************************************
+ * struct UnicodeRange
+ ******************************************************************************/
+int32_t UnicodeRange::range(int32_t bit) {
+  if (bit < 0 || bit > kLast) {
+    return -1;
+  }
+  return bit;
+}
+
+/******************************************************************************
+ * class OS2Table
+ ******************************************************************************/
+OS2Table::~OS2Table() {}
+
+int32_t OS2Table::TableVersion() {
+  return data_->ReadUShort(Offset::kVersion);
+}
+
+int32_t OS2Table::XAvgCharWidth() {
+  return data_->ReadShort(Offset::kXAvgCharWidth);
+}
+
+int32_t OS2Table::UsWeightClass() {
+  return data_->ReadUShort(Offset::kUsWeightClass);
+}
+
+int32_t OS2Table::UsWidthClass() {
+  return data_->ReadUShort(Offset::kUsWidthClass);
+}
+
+int32_t OS2Table::FsType() {
+  return data_->ReadUShort(Offset::kFsType);
+}
+
+int32_t OS2Table::YSubscriptXSize() {
+  return data_->ReadShort(Offset::kYSubscriptXSize);
+}
+
+int32_t OS2Table::YSubscriptYSize() {
+  return data_->ReadShort(Offset::kYSubscriptYSize);
+}
+
+int32_t OS2Table::YSubscriptXOffset() {
+  return data_->ReadShort(Offset::kYSubscriptXOffset);
+}
+
+int32_t OS2Table::YSubscriptYOffset() {
+  return data_->ReadShort(Offset::kYSubscriptYOffset);
+}
+
+int32_t OS2Table::YSuperscriptXSize() {
+  return data_->ReadShort(Offset::kYSuperscriptXSize);
+}
+
+int32_t OS2Table::YSuperscriptYSize() {
+  return data_->ReadShort(Offset::kYSuperscriptYSize);
+}
+
+int32_t OS2Table::YSuperscriptXOffset() {
+  return data_->ReadShort(Offset::kYSuperscriptXOffset);
+}
+
+int32_t OS2Table::YSuperscriptYOffset() {
+  return data_->ReadShort(Offset::kYSuperscriptYOffset);
+}
+
+int32_t OS2Table::YStrikeoutSize() {
+  return data_->ReadShort(Offset::kYStrikeoutSize);
+}
+
+int32_t OS2Table::YStrikeoutPosition() {
+  return data_->ReadShort(Offset::kYStrikeoutPosition);
+}
+
+int32_t OS2Table::SFamilyClass() {
+  return data_->ReadShort(Offset::kSFamilyClass);
+}
+
+void OS2Table::Panose(ByteVector* value) {
+  assert(value);
+  value->clear();
+  value->resize(10);
+  data_->ReadBytes(Offset::kPanose, &((*value)[0]), 0, 10);
+}
+
+int64_t OS2Table::UlUnicodeRange1() {
+  return data_->ReadULong(Offset::kUlUnicodeRange1);
+}
+
+int64_t OS2Table::UlUnicodeRange2() {
+  return data_->ReadULong(Offset::kUlUnicodeRange2);
+}
+
+int64_t OS2Table::UlUnicodeRange3() {
+  return data_->ReadULong(Offset::kUlUnicodeRange3);
+}
+
+int64_t OS2Table::UlUnicodeRange4() {
+  return data_->ReadULong(Offset::kUlUnicodeRange4);
+}
+
+void OS2Table::AchVendId(ByteVector* b) {
+  assert(b);
+  b->clear();
+  b->resize(4);
+  data_->ReadBytes(Offset::kAchVendId, &((*b)[0]), 0, 4);
+}
+
+int32_t OS2Table::FsSelection() {
+  return data_->ReadUShort(Offset::kFsSelection);
+}
+
+int32_t OS2Table::UsFirstCharIndex() {
+  return data_->ReadUShort(Offset::kUsFirstCharIndex);
+}
+
+int32_t OS2Table::UsLastCharIndex() {
+  return data_->ReadUShort(Offset::kUsLastCharIndex);
+}
+
+int32_t OS2Table::STypoAscender() {
+  return data_->ReadShort(Offset::kSTypoAscender);
+}
+
+int32_t OS2Table::STypoDescender() {
+  return data_->ReadShort(Offset::kSTypoDescender);
+}
+
+int32_t OS2Table::STypoLineGap() {
+  return data_->ReadShort(Offset::kSTypoLineGap);
+}
+
+int32_t OS2Table::UsWinAscent() {
+  return data_->ReadUShort(Offset::kUsWinAscent);
+}
+
+int32_t OS2Table::UsWinDescent() {
+  return data_->ReadUShort(Offset::kUsWinDescent);
+}
+
+int64_t OS2Table::UlCodePageRange1() {
+  return data_->ReadULong(Offset::kUlCodePageRange1);
+}
+
+int64_t OS2Table::UlCodePageRange2() {
+  return data_->ReadULong(Offset::kUlCodePageRange2);
+}
+
+int32_t OS2Table::SxHeight() {
+  return data_->ReadShort(Offset::kSxHeight);
+}
+
+int32_t OS2Table::SCapHeight() {
+  return data_->ReadShort(Offset::kSCapHeight);
+}
+
+int32_t OS2Table::UsDefaultChar() {
+  return data_->ReadUShort(Offset::kUsDefaultChar);
+}
+
+int32_t OS2Table::UsBreakChar() {
+  return data_->ReadUShort(Offset::kUsBreakChar);
+}
+
+int32_t OS2Table::UsMaxContext() {
+  return data_->ReadUShort(Offset::kUsMaxContext);
+}
+
+OS2Table::OS2Table(Header* header, ReadableFontData* data)
+    : Table(header, data) {
+}
+
+/******************************************************************************
+ * class OS2Table::Builder
+ ******************************************************************************/
+OS2Table::Builder::Builder(Header* header, WritableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+OS2Table::Builder::Builder(Header* header, ReadableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+OS2Table::Builder::~Builder() {}
+
+CALLER_ATTACH FontDataTable* OS2Table::Builder::SubBuildTable(
+    ReadableFontData* data) {
+  FontDataTablePtr table = new OS2Table(header(), data);
+  return table.Detach();
+}
+
+CALLER_ATTACH OS2Table::Builder*
+    OS2Table::Builder::CreateBuilder(Header* header,
+                                     WritableFontData* data) {
+  Ptr<OS2Table::Builder> builder;
+  builder = new OS2Table::Builder(header, data);
+  return builder.Detach();
+}
+
+int32_t OS2Table::Builder::TableVersion() {
+  return InternalReadData()->ReadUShort(Offset::kVersion);
+}
+
+void OS2Table::Builder::SetTableVersion(int32_t version) {
+  InternalWriteData()->WriteUShort(Offset::kVersion, version);
+}
+
+int32_t OS2Table::Builder::XAvgCharWidth() {
+  return InternalReadData()->ReadShort(Offset::kXAvgCharWidth);
+}
+
+void OS2Table::Builder::SetXAvgCharWidth(int32_t width) {
+  InternalWriteData()->WriteShort(Offset::kXAvgCharWidth, width);
+}
+
+int32_t OS2Table::Builder::UsWeightClass() {
+  return InternalReadData()->ReadUShort(Offset::kUsWeightClass);
+}
+
+void OS2Table::Builder::SetUsWeightClass(int32_t weight) {
+  InternalWriteData()->WriteUShort(Offset::kUsWeightClass, weight);
+}
+
+int32_t OS2Table::Builder::UsWidthClass() {
+  return InternalReadData()->ReadUShort(Offset::kUsWidthClass);
+}
+
+void OS2Table::Builder::SetUsWidthClass(int32_t width) {
+  InternalWriteData()->WriteUShort(Offset::kUsWidthClass, width);
+}
+
+int32_t OS2Table::Builder::FsType() {
+  return InternalReadData()->ReadUShort(Offset::kFsType);
+}
+
+void OS2Table::Builder::SetFsType(int32_t fs_type) {
+  InternalWriteData()->WriteUShort(Offset::kFsType, fs_type);
+}
+
+int32_t OS2Table::Builder::YSubscriptXSize() {
+  return InternalReadData()->ReadShort(Offset::kYSubscriptXSize);
+}
+
+void OS2Table::Builder::SetYSubscriptXSize(int32_t size) {
+  InternalWriteData()->WriteShort(Offset::kYSubscriptXSize, size);
+}
+
+int32_t OS2Table::Builder::YSubscriptYSize() {
+  return InternalReadData()->ReadShort(Offset::kYSubscriptYSize);
+}
+
+void OS2Table::Builder::SetYSubscriptYSize(int32_t size) {
+  InternalWriteData()->WriteShort(Offset::kYSubscriptYSize, size);
+}
+
+int32_t OS2Table::Builder::YSubscriptXOffset() {
+  return InternalReadData()->ReadShort(Offset::kYSubscriptXOffset);
+}
+
+void OS2Table::Builder::SetYSubscriptXOffset(int32_t offset) {
+  InternalWriteData()->WriteShort(Offset::kYSubscriptXOffset, offset);
+}
+
+int32_t OS2Table::Builder::YSubscriptYOffset() {
+  return InternalReadData()->ReadShort(Offset::kYSubscriptYOffset);
+}
+
+void OS2Table::Builder::SetYSubscriptYOffset(int32_t offset) {
+  InternalWriteData()->WriteShort(Offset::kYSubscriptYOffset, offset);
+}
+
+int32_t OS2Table::Builder::YSuperscriptXSize() {
+  return InternalReadData()->ReadShort(Offset::kYSuperscriptXSize);
+}
+
+void OS2Table::Builder::SetYSuperscriptXSize(int32_t size) {
+  InternalWriteData()->WriteShort(Offset::kYSuperscriptXSize, size);
+}
+
+int32_t OS2Table::Builder::YSuperscriptYSize() {
+  return InternalReadData()->ReadShort(Offset::kYSuperscriptYSize);
+}
+
+void OS2Table::Builder::SetYSuperscriptYSize(int32_t size) {
+  InternalWriteData()->WriteShort(Offset::kYSuperscriptYSize, size);
+}
+
+int32_t OS2Table::Builder::YSuperscriptXOffset() {
+  return InternalReadData()->ReadShort(Offset::kYSuperscriptXOffset);
+}
+
+void OS2Table::Builder::SetYSuperscriptXOffset(int32_t offset) {
+  InternalWriteData()->WriteShort(Offset::kYSuperscriptXOffset, offset);
+}
+
+int32_t OS2Table::Builder::YSuperscriptYOffset() {
+  return InternalReadData()->ReadShort(Offset::kYSuperscriptYOffset);
+}
+
+void OS2Table::Builder::SetYSuperscriptYOffset(int32_t offset) {
+  InternalWriteData()->WriteShort(Offset::kYSuperscriptYOffset, offset);
+}
+
+int32_t OS2Table::Builder::YStrikeoutSize() {
+  return InternalReadData()->ReadShort(Offset::kYStrikeoutSize);
+}
+
+void OS2Table::Builder::SetYStrikeoutSize(int32_t size) {
+  InternalWriteData()->WriteShort(Offset::kYStrikeoutSize, size);
+}
+
+int32_t OS2Table::Builder::YStrikeoutPosition() {
+  return InternalReadData()->ReadShort(Offset::kYStrikeoutPosition);
+}
+
+void OS2Table::Builder::SetYStrikeoutPosition(int32_t position) {
+  InternalWriteData()->WriteShort(Offset::kYStrikeoutPosition, position);
+}
+
+int32_t OS2Table::Builder::SFamilyClass() {
+  return InternalReadData()->ReadShort(Offset::kSFamilyClass);
+}
+
+void OS2Table::Builder::SetSFamilyClass(int32_t family) {
+  InternalWriteData()->WriteShort(Offset::kSFamilyClass, family);
+}
+
+void OS2Table::Builder::Panose(ByteVector* value) {
+  assert(value);
+  value->clear();
+  value->resize(Offset::kPanoseLength);
+  InternalReadData()->ReadBytes(Offset::kPanose,
+                                &((*value)[0]),
+                                0,
+                                Offset::kPanoseLength);
+}
+
+void OS2Table::Builder::SetPanose(ByteVector* panose) {
+  assert(panose);
+  if (panose->size() != Offset::kPanoseLength) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IllegalArgumentException("Panose bytes must be exactly 10 in length");
+#endif
+    return;
+  }
+  InternalWriteData()->WriteBytes(Offset::kPanose, panose);
+}
+
+int64_t OS2Table::Builder::UlUnicodeRange1() {
+  return InternalReadData()->ReadULong(Offset::kUlUnicodeRange1);
+}
+
+void OS2Table::Builder::SetUlUnicodeRange1(int64_t range) {
+  InternalWriteData()->WriteULong(Offset::kUlUnicodeRange1, range);
+}
+
+int64_t OS2Table::Builder::UlUnicodeRange2() {
+  return InternalReadData()->ReadULong(Offset::kUlUnicodeRange2);
+}
+
+void OS2Table::Builder::SetUlUnicodeRange2(int64_t range) {
+  InternalWriteData()->WriteULong(Offset::kUlUnicodeRange2, range);
+}
+
+int64_t OS2Table::Builder::UlUnicodeRange3() {
+  return InternalReadData()->ReadULong(Offset::kUlUnicodeRange3);
+}
+
+void OS2Table::Builder::SetUlUnicodeRange3(int64_t range) {
+  InternalWriteData()->WriteULong(Offset::kUlUnicodeRange3, range);
+}
+
+int64_t OS2Table::Builder::UlUnicodeRange4() {
+  return InternalReadData()->ReadULong(Offset::kUlUnicodeRange4);
+}
+
+void OS2Table::Builder::SetUlUnicodeRange4(int64_t range) {
+  InternalWriteData()->WriteULong(Offset::kUlUnicodeRange4, range);
+}
+
+void OS2Table::Builder::AchVendId(ByteVector* b) {
+  assert(b);
+  b->clear();
+  b->resize(4);
+  InternalReadData()->ReadBytes(Offset::kAchVendId, &((*b)[0]), 0, 4);
+}
+
+void OS2Table::Builder::SetAchVendId(ByteVector* b) {
+  assert(b);
+  assert(b->size());
+  InternalWriteData()->WriteBytesPad(Offset::kAchVendId,
+                                     b,
+                                     0,
+                                     std::min<size_t>(
+                                         (size_t)Offset::kAchVendIdLength,
+                                         b->size()),
+                                     static_cast<byte_t>(' '));
+}
+
+int32_t OS2Table::Builder::FsSelection() {
+  return InternalReadData()->ReadUShort(Offset::kFsSelection);
+}
+
+void OS2Table::Builder::SetFsSelection(int32_t fs_selection) {
+  InternalWriteData()->WriteUShort(Offset::kFsSelection, fs_selection);
+}
+
+int32_t OS2Table::Builder::UsFirstCharIndex() {
+  return InternalReadData()->ReadUShort(Offset::kUsFirstCharIndex);
+}
+
+void OS2Table::Builder::SetUsFirstCharIndex(int32_t first_index) {
+  InternalWriteData()->WriteUShort(Offset::kUsFirstCharIndex, first_index);
+}
+
+int32_t OS2Table::Builder::UsLastCharIndex() {
+  return InternalReadData()->ReadUShort(Offset::kUsLastCharIndex);
+}
+
+void OS2Table::Builder::SetUsLastCharIndex(int32_t last_index) {
+  InternalWriteData()->WriteUShort(Offset::kUsLastCharIndex, last_index);
+}
+
+int32_t OS2Table::Builder::STypoAscender() {
+  return InternalReadData()->ReadShort(Offset::kSTypoAscender);
+}
+
+void OS2Table::Builder::SetSTypoAscender(int32_t ascender) {
+  InternalWriteData()->WriteShort(Offset::kSTypoAscender, ascender);
+}
+
+int32_t OS2Table::Builder::STypoDescender() {
+  return InternalReadData()->ReadShort(Offset::kSTypoDescender);
+}
+
+void OS2Table::Builder::SetSTypoDescender(int32_t descender) {
+  InternalWriteData()->WriteShort(Offset::kSTypoDescender, descender);
+}
+
+int32_t OS2Table::Builder::STypoLineGap() {
+  return InternalReadData()->ReadShort(Offset::kSTypoLineGap);
+}
+
+void OS2Table::Builder::SetSTypoLineGap(int32_t line_gap) {
+  InternalWriteData()->WriteShort(Offset::kSTypoLineGap, line_gap);
+}
+
+int32_t OS2Table::Builder::UsWinAscent() {
+  return InternalReadData()->ReadUShort(Offset::kUsWinAscent);
+}
+
+void OS2Table::Builder::SetUsWinAscent(int32_t ascent) {
+  InternalWriteData()->WriteUShort(Offset::kUsWinAscent, ascent);
+}
+
+int32_t OS2Table::Builder::UsWinDescent() {
+  return InternalReadData()->ReadUShort(Offset::kUsWinDescent);
+}
+
+void OS2Table::Builder::SetUsWinDescent(int32_t descent) {
+  InternalWriteData()->WriteUShort(Offset::kUsWinDescent, descent);
+}
+
+int64_t OS2Table::Builder::UlCodePageRange1() {
+  return InternalReadData()->ReadULong(Offset::kUlCodePageRange1);
+}
+
+void OS2Table::Builder::SetUlCodePageRange1(int64_t range) {
+  InternalWriteData()->WriteULong(Offset::kUlCodePageRange1, range);
+}
+
+int64_t OS2Table::Builder::UlCodePageRange2() {
+  return InternalReadData()->ReadULong(Offset::kUlCodePageRange2);
+}
+
+void OS2Table::Builder::SetUlCodePageRange2(int64_t range) {
+  InternalWriteData()->WriteULong(Offset::kUlCodePageRange2, range);
+}
+
+int32_t OS2Table::Builder::SxHeight() {
+  return InternalReadData()->ReadShort(Offset::kSxHeight);
+}
+
+void OS2Table::Builder::SetSxHeight(int32_t height) {
+  InternalWriteData()->WriteShort(Offset::kSxHeight, height);
+}
+
+int32_t OS2Table::Builder::SCapHeight() {
+  return InternalReadData()->ReadShort(Offset::kSCapHeight);
+}
+
+void OS2Table::Builder::SetSCapHeight(int32_t height) {
+  InternalWriteData()->WriteShort(Offset::kSCapHeight, height);
+}
+
+int32_t OS2Table::Builder::UsDefaultChar() {
+  return InternalReadData()->ReadUShort(Offset::kUsDefaultChar);
+}
+
+void OS2Table::Builder::SetUsDefaultChar(int32_t default_char) {
+  InternalWriteData()->WriteUShort(Offset::kUsDefaultChar, default_char);
+}
+
+int32_t OS2Table::Builder::UsBreakChar() {
+  return InternalReadData()->ReadUShort(Offset::kUsBreakChar);
+}
+
+void OS2Table::Builder::SetUsBreakChar(int32_t break_char) {
+  InternalWriteData()->WriteUShort(Offset::kUsBreakChar, break_char);
+}
+
+int32_t OS2Table::Builder::UsMaxContext() {
+  return InternalReadData()->ReadUShort(Offset::kUsMaxContext);
+}
+
+void OS2Table::Builder::SetUsMaxContext(int32_t max_context) {
+  InternalWriteData()->WriteUShort(Offset::kUsMaxContext, max_context);
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/core/os2_table.h b/cpp/src/sfntly/table/core/os2_table.h
new file mode 100644
index 0000000..00d26d2
--- /dev/null
+++ b/cpp/src/sfntly/table/core/os2_table.h
@@ -0,0 +1,508 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_
+
+#include "sfntly/port/refcount.h"
+#include "sfntly/table/table.h"
+#include "sfntly/table/table_based_table_builder.h"
+
+namespace sfntly {
+
+struct WeightClass {
+  enum {
+    kThin = 100,
+    kExtraLight = 200,
+    kUltraLight = 200,
+    kLight = 300,
+    kNormal = 400,
+    kRegular = 400,
+    kMedium = 500,
+    kSemiBold = 600,
+    kDemiBold = 600,
+    kBold = 700,
+    kExtraBold = 800,
+    kUltraBold = 800,
+    kBlack = 900,
+    kHeavy = 900
+  };
+};
+
+struct WidthClass {
+  enum {
+    kUltraCondensed = 1,
+    kExtraCondensed = 2,
+    kCondensed = 3,
+    kSemiCondensed = 4,
+    kMedium = 5,
+    kNormal = 5,
+    kSemiExpanded = 6,
+    kExpanded = 7,
+    kExtraExpanded = 8,
+    kUltraExpanded = 9
+  };
+};
+
+// Flags to indicate the embedding licensing rights for a font.
+struct EmbeddingFlags {
+  enum {
+    kReserved0 = 1 << 0,
+    kRestrictedLicenseEmbedding = 1 << 1,
+    kPreviewAndPrintEmbedding = 1 << 2,
+    kEditableEmbedding = 1 << 3,
+    kReserved4 = 1 << 4,
+    kReserved5 = 1 << 5,
+    kReserved6 = 1 << 6,
+    kReserved7 = 1 << 7,
+    kNoSubsetting = 1 << 8,
+    kBitmapEmbeddingOnly = 1 << 9,
+    kReserved10 = 1 << 10,
+    kReserved11 = 1 << 11,
+    kReserved12 = 1 << 12,
+    kReserved13 = 1 << 13,
+    kReserved14 = 1 << 14,
+    kReserved15 = 1 << 15
+  };
+};
+
+struct UnicodeRange {
+  enum {
+    // Do NOT reorder. This enum relies on the ordering of the data matching the
+    // ordinal numbers of the properties.
+    kBasicLatin,
+    kLatin1Supplement,
+    kLatinExtendedA,
+    kLatinExtendedB,
+    kIPAExtensions,
+    kSpacingModifierLetters,
+    kCombiningDiacriticalMarks,
+    kGreekAndCoptic,
+    kCoptic,
+    kCyrillic,
+    kArmenian,
+    kHebrew,
+    kVai,
+    kArabic,
+    kNKo,
+    kDevanagari,
+    kBengali,
+    kGurmukhi,
+    kGujarati,
+    kOriya,
+    kTamil,
+    kTelugu,
+    kKannada,
+    kMalayalam,
+    kThai,
+    kLao,
+    kGeorgian,
+    kBalinese,
+    kHangulJamo,
+    kLatinExtendedAdditional,
+    kGreekExtended,
+    kGeneralPunctuation,
+    kSuperscriptsAndSubscripts,
+    kCurrencySymbols,
+    kNumberForms,
+    kArrows,
+    kMathematicalOperators,
+    kMiscTechnical,
+    kControlPictures,
+    kOCR,
+    kEnclosedAlphanumerics,
+    kBoxDrawing,
+    kBlockElements,
+    kGeometricShapes,
+    kMiscSymbols,
+    kDingbats,
+    kCJKSymbolsAndPunctuation,
+    kHiragana,
+    kKatakana,
+    kBopomofo,
+    kHangulCompatibilityJamo,
+    kPhagspa,
+    kEnclosedCJKLettersAndMonths,
+    kCJKCompatibility,
+    kHangulSyllables,
+    kNonPlane0,
+    kPhoenician,
+    kCJKUnifiedIdeographs,
+    kPrivateUseAreaPlane0,
+    kCJKStrokes,
+    kAlphabeticPresentationForms,
+    kArabicPresentationFormsA,
+    kCombiningHalfMarks,
+    kVerticalForms,
+    kSmallFormVariants,
+    kArabicPresentationFormsB,
+    kHalfwidthAndFullwidthForms,
+    kSpecials,
+    kTibetan,
+    kSyriac,
+    kThaana,
+    kSinhala,
+    kMyanmar,
+    kEthiopic,
+    kCherokee,
+    kUnifiedCanadianAboriginalSyllabics,
+    kOgham,
+    kRunic,
+    kKhmer,
+    kMongolian,
+    kBraillePatterns,
+    kYiSyllables,
+    kTagalog,
+    kOldItalic,
+    kGothic,
+    kDeseret,
+    kMusicalSymbols,
+    kMathematicalAlphanumericSymbols,
+    kPrivateUsePlane15And16,
+    kVariationSelectors,
+    kTags,
+    kLimbu,
+    kTaiLe,
+    kNewTaiLue,
+    kBuginese,
+    kGlagolitic,
+    kTifnagh,
+    kYijingHexagramSymbols,
+    kSylotiNagari,
+    kLinearB,
+    kAncientGreekNumbers,
+    kUgaritic,
+    kOldPersian,
+    kShavian,
+    kOsmanya,
+    kCypriotSyllabary,
+    kKharoshthi,
+    kTaiXuanJingSymbols,
+    kCuneiform,
+    kCountingRodNumerals,
+    kSudanese,
+    kLepcha,
+    kOlChiki,
+    kSaurashtra,
+    kKayahLi,
+    kRejang,
+    kCharm,
+    kAncientSymbols,
+    kPhaistosDisc,
+    kCarian,
+    kDominoTiles,
+    kReserved123,
+    kReserved124,
+    kReserved125,
+    kReserved126,
+    kReserved127,
+    kLast = kReserved127
+  };
+
+  int32_t range(int32_t bit);
+  // UNIMPLEMENTED: EnumSet<UnicodeRange> asSet(long range1, long range2,
+  //                                            long range3, long range4)
+  //                long[] asArray(EnumSet<UnicodeRange> rangeSet)
+};
+
+struct FsSelection {
+  enum {
+    kITALIC = 1 << 0,
+    kUNDERSCORE = 1 << 1,
+    kNEGATIVE = 1 << 2,
+    kOUTLINED = 1 << 3,
+    kSTRIKEOUT = 1 << 4,
+    kBOLD = 1 << 5,
+    kREGULAR = 1 << 6,
+    kUSE_TYPO_METRICS = 1 << 7,
+    kWWS = 1 << 8,
+    kOBLIQUE = 1 << 9
+  };
+  // UNIMPLEMENTED: EnumSet<FsSelection> asSet(long range1, long range2,
+  //                                           long range3, long range4)
+  //                long[] asArray(EnumSet<FsSelection> rangeSet)
+};
+
+// C++ port only: C++ does not support 64-bit enums until C++0x.  For better
+// portability, we need to use static const int64_t instead.
+struct CodePageRange {
+  static const int64_t kLatin1_1252;
+  static const int64_t kLatin2_1250;
+  static const int64_t kCyrillic_1251;
+  static const int64_t kGreek_1253;
+  static const int64_t kTurkish_1254;
+  static const int64_t kHebrew_1255;
+  static const int64_t kArabic_1256;
+  static const int64_t kWindowsBaltic_1257;
+  static const int64_t kVietnamese_1258;
+  static const int64_t kAlternateANSI9;
+  static const int64_t kAlternateANSI10;
+  static const int64_t kAlternateANSI11;
+  static const int64_t kAlternateANSI12;
+  static const int64_t kAlternateANSI13;
+  static const int64_t kAlternateANSI14;
+  static const int64_t kAlternateANSI15;
+  static const int64_t kThai_874;
+  static const int64_t kJapanJIS_932;
+  static const int64_t kChineseSimplified_936;
+  static const int64_t kKoreanWansung_949;
+  static const int64_t kChineseTraditional_950;
+  static const int64_t kKoreanJohab_1361;
+  static const int64_t kAlternateANSI22;
+  static const int64_t kAlternateANSI23;
+  static const int64_t kAlternateANSI24;
+  static const int64_t kAlternateANSI25;
+  static const int64_t kAlternateANSI26;
+  static const int64_t kAlternateANSI27;
+  static const int64_t kAlternateANSI28;
+  static const int64_t kMacintoshCharacterSet;
+  static const int64_t kOEMCharacterSet;
+  static const int64_t kSymbolCharacterSet;
+  static const int64_t kReservedForOEM32;
+  static const int64_t kReservedForOEM33;
+  static const int64_t kReservedForOEM34;
+  static const int64_t kReservedForOEM35;
+  static const int64_t kReservedForOEM36;
+  static const int64_t kReservedForOEM37;
+  static const int64_t kReservedForOEM38;
+  static const int64_t kReservedForOEM39;
+  static const int64_t kReservedForOEM40;
+  static const int64_t kReservedForOEM41;
+  static const int64_t kReservedForOEM42;
+  static const int64_t kReservedForOEM43;
+  static const int64_t kReservedForOEM44;
+  static const int64_t kReservedForOEM45;
+  static const int64_t kReservedForOEM46;
+  static const int64_t kReservedForOEM47;
+  static const int64_t kIBMGreek_869;
+  static const int64_t kMSDOSRussion_866;
+  static const int64_t kMSDOSNordic_865;
+  static const int64_t kArabic_864;
+  static const int64_t kMSDOSCanadianFrench_863;
+  static const int64_t kHebrew_862;
+  static const int64_t kMSDOSIcelandic_861;
+  static const int64_t kMSDOSPortugese_860;
+  static const int64_t kIBMTurkish_857;
+  static const int64_t kIBMCyrillic_855;
+  static const int64_t kLatin2_852;
+  static const int64_t kMSDOSBaltic_775;
+  static const int64_t kGreek_737;
+  static const int64_t kArabic_708;
+  static const int64_t kLatin1_850;
+  static const int64_t kUS_437;
+
+  // UNIMPLEMENTED: EnumSet<CodePageRange> asSet(long range1, long range2,
+  //                                             long range3, long range4)
+  //                long[] asArray(EnumSet<CodePageRange> rangeSet)
+};
+
+// An OS/2 table - 'OS/2'.
+class OS2Table : public Table, public RefCounted<OS2Table> {
+ public:
+  // A builder for the OS/2 table = 'OS/2'.
+  class Builder : public TableBasedTableBuilder, public RefCounted<Builder> {
+   public:
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+
+    int32_t TableVersion();
+    void SetTableVersion(int32_t version);
+    int32_t XAvgCharWidth();
+    void SetXAvgCharWidth(int32_t width);
+    int32_t UsWeightClass();
+    void SetUsWeightClass(int32_t weight);
+    int32_t UsWidthClass();
+    void SetUsWidthClass(int32_t width);
+    // UNIMPLEMENTED: EnumSet<EmbeddingFlags> fsType()
+    //                void setFsType(EnumSeT<EmbeddingFlags> flagSet)
+    int32_t FsType();
+    void SetFsType(int32_t fs_type);
+    int32_t YSubscriptXSize();
+    void SetYSubscriptXSize(int32_t size);
+    int32_t YSubscriptYSize();
+    void SetYSubscriptYSize(int32_t size);
+    int32_t YSubscriptXOffset();
+    void SetYSubscriptXOffset(int32_t offset);
+    int32_t YSubscriptYOffset();
+    void SetYSubscriptYOffset(int32_t offset);
+    int32_t YSuperscriptXSize();
+    void SetYSuperscriptXSize(int32_t size);
+    int32_t YSuperscriptYSize();
+    void SetYSuperscriptYSize(int32_t size);
+    int32_t YSuperscriptXOffset();
+    void SetYSuperscriptXOffset(int32_t offset);
+    int32_t YSuperscriptYOffset();
+    void SetYSuperscriptYOffset(int32_t offset);
+    int32_t YStrikeoutSize();
+    void SetYStrikeoutSize(int32_t size);
+    int32_t YStrikeoutPosition();
+    void SetYStrikeoutPosition(int32_t position);
+    int32_t SFamilyClass();
+    void SetSFamilyClass(int32_t family);
+    void Panose(ByteVector* value);
+    void SetPanose(ByteVector* panose);
+    int64_t UlUnicodeRange1();
+    void SetUlUnicodeRange1(int64_t range);
+    int64_t UlUnicodeRange2();
+    void SetUlUnicodeRange2(int64_t range);
+    int64_t UlUnicodeRange3();
+    void SetUlUnicodeRange3(int64_t range);
+    int64_t UlUnicodeRange4();
+    void SetUlUnicodeRange4(int64_t range);
+    // UNIMPLEMENTED: EnumSet<UnicodeRange> UlUnicodeRange()
+    //                setUlUnicodeRange(EnumSet<UnicodeRange> rangeSet)
+    void AchVendId(ByteVector* b);
+    // This field is 4 bytes in length and only the first 4 bytes of the byte
+    // array will be written. If the byte array is less than 4 bytes it will be
+    // padded out with space characters (0x20).
+    // @param b ach Vendor Id
+    void SetAchVendId(ByteVector* b);
+    // UNIMPLEMENTED: public EnumSet<FsSelection> fsSelection()
+    int32_t FsSelection();
+    void SetFsSelection(int32_t fs_selection);
+    int32_t UsFirstCharIndex();
+    void SetUsFirstCharIndex(int32_t first_index);
+    int32_t UsLastCharIndex();
+    void SetUsLastCharIndex(int32_t last_index);
+    int32_t STypoAscender();
+    void SetSTypoAscender(int32_t ascender);
+    int32_t STypoDescender();
+    void SetSTypoDescender(int32_t descender);
+    int32_t STypoLineGap();
+    void SetSTypoLineGap(int32_t line_gap);
+    int32_t UsWinAscent();
+    void SetUsWinAscent(int32_t ascent);
+    int32_t UsWinDescent();
+    void SetUsWinDescent(int32_t descent);
+    int64_t UlCodePageRange1();
+    void SetUlCodePageRange1(int64_t range);
+    int64_t UlCodePageRange2();
+    void SetUlCodePageRange2(int64_t range);
+    // UNIMPLEMENTED: EnumSet<CodePageRange> ulCodePageRange()
+    //                void setUlCodePageRange(EnumSet<CodePageRange> rangeSet)
+    int32_t SxHeight();
+    void SetSxHeight(int32_t height);
+    int32_t SCapHeight();
+    void SetSCapHeight(int32_t height);
+    int32_t UsDefaultChar();
+    void SetUsDefaultChar(int32_t default_char);
+    int32_t UsBreakChar();
+    void SetUsBreakChar(int32_t break_char);
+    int32_t UsMaxContext();
+    void SetUsMaxContext(int32_t max_context);
+  };
+
+  ~OS2Table();
+
+  int32_t TableVersion();
+  int32_t XAvgCharWidth();
+  int32_t UsWeightClass();
+  int32_t UsWidthClass();
+  // UNIMPLEMENTED: public EnumSet<EmbeddingFlags> fsType()
+  int32_t FsType();
+  int32_t YSubscriptXSize();
+  int32_t YSubscriptYSize();
+  int32_t YSubscriptXOffset();
+  int32_t YSubscriptYOffset();
+  int32_t YSuperscriptXSize();
+  int32_t YSuperscriptYSize();
+  int32_t YSuperscriptXOffset();
+  int32_t YSuperscriptYOffset();
+  int32_t YStrikeoutSize();
+  int32_t YStrikeoutPosition();
+  int32_t SFamilyClass();
+  void Panose(ByteVector* value);
+  int64_t UlUnicodeRange1();
+  int64_t UlUnicodeRange2();
+  int64_t UlUnicodeRange3();
+  int64_t UlUnicodeRange4();
+  // UNIMPLEMENTED: public EnumSet<UnicodeRange> UlUnicodeRange()
+  void AchVendId(ByteVector* b);
+  // UNIMPLEMENTED: public EnumSet<FsSelection> fsSelection()
+  int32_t FsSelection();
+  int32_t UsFirstCharIndex();
+  int32_t UsLastCharIndex();
+  int32_t STypoAscender();
+  int32_t STypoDescender();
+  int32_t STypoLineGap();
+  int32_t UsWinAscent();
+  int32_t UsWinDescent();
+  int64_t UlCodePageRange1();
+  int64_t UlCodePageRange2();
+  // UNIMPLEMENTED: public EnumSet<CodePageRange> ulCodePageRange()
+  int32_t SxHeight();
+  int32_t SCapHeight();
+  int32_t UsDefaultChar();
+  int32_t UsBreakChar();
+  int32_t UsMaxContext();
+
+ private:
+  struct Offset {
+    enum {
+      kVersion = 0,
+      kXAvgCharWidth = 2,
+      kUsWeightClass = 4,
+      kUsWidthClass = 6,
+      kFsType = 8,
+      kYSubscriptXSize = 10,
+      kYSubscriptYSize = 12,
+      kYSubscriptXOffset = 14,
+      kYSubscriptYOffset = 16,
+      kYSuperscriptXSize = 18,
+      kYSuperscriptYSize = 20,
+      kYSuperscriptXOffset = 22,
+      kYSuperscriptYOffset = 24,
+      kYStrikeoutSize = 26,
+      kYStrikeoutPosition = 28,
+      kSFamilyClass = 30,
+      kPanose = 32,
+      kPanoseLength = 10,  // Length of panose bytes.
+      kUlUnicodeRange1 = 42,
+      kUlUnicodeRange2 = 46,
+      kUlUnicodeRange3 = 50,
+      kUlUnicodeRange4 = 54,
+      kAchVendId = 58,
+      kAchVendIdLength = 4,  // Length of ach vend id bytes.
+      kFsSelection = 62,
+      kUsFirstCharIndex = 64,
+      kUsLastCharIndex = 66,
+      kSTypoAscender = 68,
+      kSTypoDescender = 70,
+      kSTypoLineGap = 72,
+      kUsWinAscent = 74,
+      kUsWinDescent = 76,
+      kUlCodePageRange1 = 78,
+      kUlCodePageRange2 = 82,
+      kSxHeight = 86,
+      kSCapHeight = 88,
+      kUsDefaultChar = 90,
+      kUsBreakChar = 92,
+      kUsMaxContext = 94
+    };
+  };
+
+  OS2Table(Header* header, ReadableFontData* data);
+};
+typedef Ptr<OS2Table> OS2TablePtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_CORE_OS2_TABLE_H_
diff --git a/cpp/src/sfntly/table/font_data_table.cc b/cpp/src/sfntly/table/font_data_table.cc
new file mode 100644
index 0000000..0e27f7a
--- /dev/null
+++ b/cpp/src/sfntly/table/font_data_table.cc
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/font_data_table.h"
+
+#include "sfntly/data/font_output_stream.h"
+
+namespace sfntly {
+
+/******************************************************************************
+ * FontDataTable class
+ ******************************************************************************/
+
+FontDataTable::FontDataTable(ReadableFontData* data) {
+  data_ = data;
+}
+
+FontDataTable::~FontDataTable() {}
+
+ReadableFontData* FontDataTable::ReadFontData() {
+  return data_;
+}
+
+int32_t FontDataTable::DataLength() {
+  return data_->Length();
+}
+
+int32_t FontDataTable::Serialize(OutputStream* os) {
+  return data_->CopyTo(os);
+}
+
+int32_t FontDataTable::Serialize(WritableFontData* data) {
+  return data_->CopyTo(data);
+}
+
+/******************************************************************************
+ * FontDataTable::Builder class
+ ******************************************************************************/
+CALLER_ATTACH WritableFontData* FontDataTable::Builder::Data() {
+  WritableFontDataPtr new_data;
+  if (model_changed_) {
+    if (!SubReadyToSerialize()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IOException("Table not ready to build.");
+#endif
+      return NULL;
+    }
+    int32_t size = SubDataSizeToSerialize();
+    new_data.Attach(WritableFontData::CreateWritableFontData(size));
+    SubSerialize(new_data);
+  } else {
+    ReadableFontDataPtr data = InternalReadData();
+    new_data.Attach(WritableFontData::CreateWritableFontData(
+                        data != NULL ? data->Length() : 0));
+    if (data != NULL) {
+      data->CopyTo(new_data);
+    }
+  }
+  return new_data.Detach();
+}
+
+void FontDataTable::Builder::SetData(ReadableFontData* data) {
+  InternalSetData(data, true);
+}
+
+
+CALLER_ATTACH FontDataTable* FontDataTable::Builder::Build() {
+  FontDataTablePtr table;  // NULL default table
+  ReadableFontDataPtr data = InternalReadData();
+  if (model_changed_) {
+    // Let subclass serialize from model.
+    if (!SubReadyToSerialize()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IOException("Table not ready to build.");
+#endif
+      return NULL;
+    }
+    int32_t size = SubDataSizeToSerialize();
+    WritableFontDataPtr new_data;
+    new_data.Attach(WritableFontData::CreateWritableFontData(size));
+    SubSerialize(new_data);
+    data = new_data;
+  }
+
+  if (data != NULL) {
+    table = SubBuildTable(data);
+    NotifyPostTableBuild(table);
+  }
+
+  r_data_.Release();
+  w_data_.Release();
+  return table;
+}
+
+bool FontDataTable::Builder::ReadyToBuild() {
+  return true;
+}
+
+ReadableFontData* FontDataTable::Builder::InternalReadData() {
+  return (r_data_ != NULL) ? r_data_.p_ :
+                             static_cast<ReadableFontData*>(w_data_.p_);
+}
+
+WritableFontData* FontDataTable::Builder::InternalWriteData() {
+  if (w_data_ == NULL) {
+    WritableFontDataPtr new_data;
+    new_data.Attach(WritableFontData::CreateWritableFontData(
+                        r_data_ == NULL ? 0 : r_data_->Length()));
+#if !defined (SFNTLY_NO_EXCEPTION)
+    try {
+#endif
+      if (r_data_) {
+        r_data_->CopyTo(new_data);
+      }
+#if !defined (SFNTLY_NO_EXCEPTION)
+    } catch (IOException& e) {
+      // TODO(stuartg): fix when IOExceptions are cleaned up
+    }
+#endif
+    InternalSetData(new_data, false);
+  }
+  return w_data_.p_;
+}
+
+FontDataTable::Builder::Builder()
+    : model_changed_(false),
+      contained_model_changed_(false),
+      data_changed_(false) {
+}
+
+FontDataTable::Builder::Builder(int32_t data_size)
+    : model_changed_(false),
+      contained_model_changed_(false),
+      data_changed_(false) {
+  w_data_.Attach(WritableFontData::CreateWritableFontData(data_size));
+}
+
+FontDataTable::Builder::Builder(WritableFontData* data)
+    : model_changed_(false),
+      contained_model_changed_(false),
+      data_changed_(false) {
+  w_data_ = data;
+}
+
+FontDataTable::Builder::Builder(ReadableFontData* data)
+    : model_changed_(false),
+      contained_model_changed_(false),
+      data_changed_(false) {
+  r_data_ = data;
+}
+
+FontDataTable::Builder::~Builder() {
+}
+
+void FontDataTable::Builder::NotifyPostTableBuild(FontDataTable* table) {
+  // Default: NOP.
+  UNREFERENCED_PARAMETER(table);
+}
+
+void FontDataTable::Builder::InternalSetData(WritableFontData* data,
+                                             bool data_changed) {
+  w_data_ = data;
+  r_data_ = NULL;
+  if (data_changed) {
+    data_changed_ = true;
+    SubDataSet();
+  }
+}
+
+void FontDataTable::Builder::InternalSetData(ReadableFontData* data,
+                                             bool data_changed) {
+  w_data_ = NULL;
+  r_data_ = data;
+  if (data_changed) {
+    data_changed_ = true;
+    SubDataSet();
+  }
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/font_data_table.h b/cpp/src/sfntly/table/font_data_table.h
new file mode 100644
index 0000000..5e437e2
--- /dev/null
+++ b/cpp/src/sfntly/table/font_data_table.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_
+
+#include "sfntly/data/readable_font_data.h"
+#include "sfntly/data/writable_font_data.h"
+#include "sfntly/port/refcount.h"
+
+namespace sfntly {
+
+// An abstract base for any table that contains a FontData. This is the root of
+// the table class hierarchy.
+class FontDataTable : virtual public RefCount {
+ public:
+  // Note: original version is abstract Builder<T extends FontDataTable>
+  //       C++ template is not designed that way so plain class is chosen.
+  class Builder : virtual public RefCount {
+   public:
+    // Get a snapshot copy of the internal data of the builder.
+    // This causes any internal data structures to be serialized to a new data
+    // object. This data object belongs to the caller and must be properly
+    // disposed of. No changes are made to the builder and any changes to the
+    // data directly do not affect the internal state. To do that a subsequent
+    // call must be made to {@link #SetData(WritableFontData)}.
+    // @return a copy of the internal data of the builder
+    CALLER_ATTACH WritableFontData* Data();
+    virtual void SetData(ReadableFontData* data);
+
+    // Note: changed from protected to avoid accessibility error in C++
+    virtual CALLER_ATTACH FontDataTable* Build();
+    virtual bool ReadyToBuild();
+
+    ReadableFontData* InternalReadData();
+    WritableFontData* InternalWriteData();
+
+    bool data_changed() { return data_changed_; }
+    bool model_changed() {
+      return current_model_changed() || contained_model_changed();
+    }
+    bool current_model_changed() { return model_changed_; }
+    bool contained_model_changed() { return contained_model_changed_; }
+
+    bool set_model_changed() { return set_model_changed(true); }
+    bool set_model_changed(bool changed) {
+      bool old = model_changed_;
+      model_changed_ = changed;
+      return old;
+    }
+
+   protected:
+    explicit Builder();
+
+    // Construct a FontDataTable.Builder with a WritableFontData backing store
+    // of size given. A positive size will create a fixed size backing store and
+    // a 0 or less size is an estimate for a growable backing store with the
+    // estimate being the absolute of the size.
+    // @param dataSize if positive then a fixed size; if 0 or less then an
+    //        estimate for a growable size
+    Builder(int32_t data_size);
+    Builder(WritableFontData* data);
+    Builder(ReadableFontData* data);
+    virtual ~Builder();
+
+    // subclass API
+    virtual void NotifyPostTableBuild(FontDataTable* table);
+    virtual int32_t SubSerialize(WritableFontData* new_data) = 0;
+    virtual bool SubReadyToSerialize() = 0;
+    virtual int32_t SubDataSizeToSerialize() = 0;
+    virtual void SubDataSet() = 0;
+    virtual CALLER_ATTACH FontDataTable*
+        SubBuildTable(ReadableFontData* data) = 0;
+
+   private:
+    void InternalSetData(WritableFontData* data, bool data_changed);
+    void InternalSetData(ReadableFontData* data, bool data_changed);
+
+    WritableFontDataPtr w_data_;
+    ReadableFontDataPtr r_data_;
+    bool model_changed_;
+    bool contained_model_changed_;  // may expand to list of submodel states
+    bool data_changed_;
+  };
+
+  explicit FontDataTable(ReadableFontData* data);
+  virtual ~FontDataTable();
+
+  // Get the readable font data for this table.
+  ReadableFontData* ReadFontData();
+
+  // Get the length of the data for this table in bytes. This is the full
+  // allocated length of the data underlying the table and may or may not
+  // include any padding.
+  virtual int32_t DataLength();
+
+  virtual int32_t Serialize(OutputStream* os);
+
+ protected:
+  virtual int32_t Serialize(WritableFontData* data);
+
+  // TODO(arthurhsu): style guide violation: protected member, need refactoring
+  ReadableFontDataPtr data_;
+};
+typedef Ptr<FontDataTable> FontDataTablePtr;
+typedef Ptr<FontDataTable::Builder> FontDataTableBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_FONT_DATA_TABLE_H_
diff --git a/cpp/src/sfntly/table/generic_table_builder.cc b/cpp/src/sfntly/table/generic_table_builder.cc
new file mode 100644
index 0000000..78e6797
--- /dev/null
+++ b/cpp/src/sfntly/table/generic_table_builder.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/generic_table_builder.h"
+
+namespace sfntly {
+
+GenericTableBuilder::~GenericTableBuilder() {}
+
+CALLER_ATTACH
+FontDataTable* GenericTableBuilder::SubBuildTable(ReadableFontData* data) {
+  // Note: In C++ port, we use GenericTable, the ref-counted version of Table
+  UNREFERENCED_PARAMETER(data);
+  Ptr<GenericTable> table = new GenericTable(header(), InternalReadData());
+  return table.Detach();
+}
+
+// static
+CALLER_ATTACH GenericTableBuilder*
+    GenericTableBuilder::CreateBuilder(Header* header, WritableFontData* data) {
+  Ptr<GenericTableBuilder> builder =
+      new GenericTableBuilder(header, data);
+  return builder.Detach();
+}
+
+GenericTableBuilder::GenericTableBuilder(Header* header,
+                                         WritableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+GenericTableBuilder::GenericTableBuilder(Header* header,
+                                         ReadableFontData* data)
+    : TableBasedTableBuilder(header, data) {
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/generic_table_builder.h b/cpp/src/sfntly/table/generic_table_builder.h
new file mode 100644
index 0000000..a100ea0
--- /dev/null
+++ b/cpp/src/sfntly/table/generic_table_builder.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_GENERIC_TABLE_BUILDER_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_GENERIC_TABLE_BUILDER_H_
+
+#include "sfntly/table/table_based_table_builder.h"
+
+namespace sfntly {
+
+// A table builder to do the minimal table building for an unknown table type.
+class GenericTableBuilder : public TableBasedTableBuilder,
+                            public RefCounted<GenericTableBuilder> {
+ public:
+  virtual ~GenericTableBuilder();
+
+  virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+
+  static CALLER_ATTACH GenericTableBuilder*
+      CreateBuilder(Header* header, WritableFontData* data);
+
+ private:
+  GenericTableBuilder(Header* header, WritableFontData* data);
+  GenericTableBuilder(Header* header, ReadableFontData* data);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_BYTE_ARRAY_TABLE_BUILDER_H_
diff --git a/cpp/src/sfntly/table/header.cc b/cpp/src/sfntly/table/header.cc
new file mode 100644
index 0000000..672ace5
--- /dev/null
+++ b/cpp/src/sfntly/table/header.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/header.h"
+
+namespace sfntly {
+
+/******************************************************************************
+ * Header class
+ ******************************************************************************/
+Header::Header(int32_t tag)
+    : tag_(tag),
+      offset_(0),
+      offset_valid_(false),
+      length_(0),
+      length_valid_(false),
+      checksum_(0),
+      checksum_valid_(false) {
+}
+
+Header::Header(int32_t tag, int32_t length)
+    : tag_(tag),
+      offset_(0),
+      offset_valid_(false),
+      length_(length),
+      length_valid_(true),
+      checksum_(0),
+      checksum_valid_(false) {
+}
+
+Header::Header(int32_t tag, int64_t checksum, int32_t offset, int32_t length)
+    : tag_(tag),
+      offset_(offset),
+      offset_valid_(true),
+      length_(length),
+      length_valid_(true),
+      checksum_(checksum),
+      checksum_valid_(true) {
+}
+
+Header::~Header() {}
+
+bool HeaderComparatorByOffset::operator() (const HeaderPtr lhs,
+                                           const HeaderPtr rhs) {
+  return lhs->offset_ > rhs->offset_;
+}
+
+bool HeaderComparatorByTag::operator() (const HeaderPtr lhs,
+                                        const HeaderPtr rhs) {
+  return lhs->tag_ > rhs->tag_;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/header.h b/cpp/src/sfntly/table/header.h
new file mode 100644
index 0000000..280e556
--- /dev/null
+++ b/cpp/src/sfntly/table/header.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_
+
+#include "sfntly/port/refcount.h"
+
+namespace sfntly {
+
+class Header : public RefCounted<Header> {
+ public:
+  // Make a partial header with only the basic info for an empty new table.
+  explicit Header(int32_t tag);
+
+  // Make a partial header with only the basic info for a new table.
+  Header(int32_t tag, int32_t length);
+
+  // Make a full header as read from an existing font.
+  Header(int32_t tag, int64_t checksum, int32_t offset, int32_t length);
+  virtual ~Header();
+
+  // Get the table tag.
+  int32_t tag() { return tag_; }
+
+  // Get the table offset. The offset is from the start of the font file.  This
+  // offset value is what was read from the font file during construction of the
+  // font. It may not be meaningful if the font was maninpulated through the
+  // builders.
+  int32_t offset() { return offset_; }
+
+  // Is the offset in the header valid. The offset will not be valid if the
+  // table was constructed during building and has no physical location in a
+  // font file.
+  bool offset_valid() { return offset_valid_; }
+
+  // Get the length of the table as recorded in the table record header.  During
+  // building the header length will reflect the length that was initially read
+  // from the font file. This may not be consistent with the current state of
+  // the data.
+  int32_t length() { return length_; }
+
+  // Is the length in the header valid. The length will not be valid if the
+  // table was constructed during building and has no physical location in a
+  // font file until the table is built from the builder.
+  bool length_valid() { return length_valid_; }
+
+  // Get the checksum for the table as recorded in the table record header.
+  int64_t checksum() { return checksum_; }
+
+  // Is the checksum valid. The checksum will not be valid if the table was
+  // constructed during building and has no physical location in a font file.
+  // Note that this does *NOT* check the validity of the checksum against
+  // the calculated checksum for the table data.
+  bool checksum_valid() { return checksum_valid_; }
+
+  // UNIMPLEMENTED: boolean equals(Object obj)
+  //                int hashCode()
+  //                string toString()
+
+ private:
+  int32_t tag_;
+  int32_t offset_;
+  bool offset_valid_;
+  int32_t length_;
+  bool length_valid_;
+  int64_t checksum_;
+  bool checksum_valid_;
+
+  friend class HeaderComparatorByOffset;
+  friend class HeaderComparatorByTag;
+};
+typedef Ptr<Header> HeaderPtr;
+
+class HeaderComparator {
+ public:
+  virtual ~HeaderComparator() {}
+  virtual bool operator()(const HeaderPtr h1,
+                          const HeaderPtr h2) = 0;
+};
+
+class HeaderComparatorByOffset : public HeaderComparator {
+ public:
+  virtual ~HeaderComparatorByOffset() {}
+  virtual bool operator()(const HeaderPtr h1,
+                          const HeaderPtr h2);
+};
+
+class HeaderComparatorByTag : public HeaderComparator {
+ public:
+  virtual ~HeaderComparatorByTag() {}
+  virtual bool operator()(const HeaderPtr h1,
+                          const HeaderPtr h2);
+};
+
+typedef std::set<HeaderPtr, HeaderComparatorByOffset> HeaderOffsetSortedSet;
+typedef std::set<HeaderPtr, HeaderComparatorByTag> HeaderTagSortedSet;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_HEADER_H_
diff --git a/cpp/src/sfntly/table/subtable.cc b/cpp/src/sfntly/table/subtable.cc
new file mode 100644
index 0000000..e5b906f
--- /dev/null
+++ b/cpp/src/sfntly/table/subtable.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/subtable.h"
+
+namespace sfntly {
+/******************************************************************************
+ * SubTable class
+ ******************************************************************************/
+SubTable::~SubTable() {}
+
+SubTable::SubTable(ReadableFontData* data, ReadableFontData* master_data)
+    : FontDataTable(data), padding_(0) {
+  master_data_ = master_data;
+}
+
+SubTable::SubTable(ReadableFontData* data)
+    : FontDataTable(data), padding_(0) {
+}
+
+/******************************************************************************
+ * SubTable::Builder class
+ ******************************************************************************/
+SubTable::Builder::~Builder() {
+}
+
+SubTable::Builder::Builder(int32_t data_size)
+    : FontDataTable::Builder(data_size) {
+}
+
+SubTable::Builder::Builder(WritableFontData* data,
+                           ReadableFontData* master_data)
+    : FontDataTable::Builder(data) {
+  master_data_ = master_data;
+}
+
+SubTable::Builder::Builder(ReadableFontData* data,
+                           ReadableFontData* master_data)
+    : FontDataTable::Builder(data) {
+  master_data_ = master_data;
+}
+
+SubTable::Builder::Builder(WritableFontData* data)
+    : FontDataTable::Builder(data) {
+}
+
+SubTable::Builder::Builder(ReadableFontData* data)
+    : FontDataTable::Builder(data) {
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/subtable.h b/cpp/src/sfntly/table/subtable.h
new file mode 100644
index 0000000..fa6f4c6
--- /dev/null
+++ b/cpp/src/sfntly/table/subtable.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_
+
+#include "sfntly/table/font_data_table.h"
+
+namespace sfntly {
+
+// An abstract base class for subtables. Subtables are smaller tables nested
+// within other tables and don't have an entry in the main font index. Examples
+// of these are the CMap subtables within CMap table (cmap) or a glyph within
+// the glyph table (glyf).
+class SubTable : public FontDataTable {
+ public:
+  class Builder : public FontDataTable::Builder {
+   public:
+    virtual ~Builder();
+
+   protected:
+    // @param data the data for the subtable being built
+    // @param master_data the data for the full table
+    Builder(int32_t data_size);
+    Builder(WritableFontData* data, ReadableFontData* master_data);
+    Builder(ReadableFontData* data, ReadableFontData* master_data);
+    explicit Builder(WritableFontData* data);
+    explicit Builder(ReadableFontData* data);
+
+    ReadableFontData* master_read_data() { return master_data_; }
+
+   private:
+    ReadableFontDataPtr master_data_;
+  };
+
+  virtual ~SubTable();
+  virtual int32_t Padding() { return padding_; }
+
+  // Sets the amount of padding that is part of the data being used by this
+  // subtable.
+  void set_padding(int32_t padding) { padding_ = padding; }
+
+ protected:
+  SubTable(ReadableFontData* data, ReadableFontData* master_data);
+
+  // Note: constructor refactored in C++ to avoid heavy lifting.
+  //       caller need to do data->Slice(offset, length) beforehand.
+  explicit SubTable(ReadableFontData* data);
+
+  ReadableFontData* master_read_data() { return master_data_; }
+
+ private:
+  // The data for the whole table in which this subtable is contained.
+  ReadableFontDataPtr master_data_;
+  int32_t padding_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_SUBTABLE_H_
diff --git a/cpp/src/sfntly/table/subtable_container_table.h b/cpp/src/sfntly/table/subtable_container_table.h
new file mode 100644
index 0000000..0f099de
--- /dev/null
+++ b/cpp/src/sfntly/table/subtable_container_table.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_
+
+#include "sfntly/table/table.h"
+
+namespace sfntly {
+
+class SubTableContainerTable : public Table {
+ public:
+  class Builder : public Table::Builder {
+   public:
+    Builder(Header* header, WritableFontData* data)
+        : Table::Builder(header, data) {
+    }
+
+    Builder(Header* header, ReadableFontData* data)
+        : Table::Builder(header, data) {
+    }
+
+    virtual ~Builder() {}
+  };
+
+  SubTableContainerTable(Header* header, ReadableFontData* data)
+      : Table(header, data) {
+  }
+
+  virtual ~SubTableContainerTable() {}
+};
+
+}  // namespace sfntly
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_SFNTLY_TABLE_SUBTABLE_CONTAINER_TABLE_H_
diff --git a/cpp/src/sfntly/table/table.cc b/cpp/src/sfntly/table/table.cc
new file mode 100644
index 0000000..cf574b8
--- /dev/null
+++ b/cpp/src/sfntly/table/table.cc
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// type.h needs to be included first because of building issues on Windows
+// Type aliases we delcare are defined in other headers and make the build
+// fail otherwise.
+#include "sfntly/port/type.h"
+#include "sfntly/table/table.h"
+
+#include "sfntly/font.h"
+#include "sfntly/tag.h"
+#include "sfntly/table/bitmap/ebdt_table.h"
+#include "sfntly/table/bitmap/eblc_table.h"
+#include "sfntly/table/bitmap/ebsc_table.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/table/core/font_header_table.h"
+#include "sfntly/table/core/horizontal_device_metrics_table.h"
+#include "sfntly/table/core/horizontal_header_table.h"
+#include "sfntly/table/core/horizontal_metrics_table.h"
+#include "sfntly/table/core/maximum_profile_table.h"
+#include "sfntly/table/core/name_table.h"
+#include "sfntly/table/core/os2_table.h"
+#include "sfntly/table/generic_table_builder.h"
+#include "sfntly/table/table_based_table_builder.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+
+namespace sfntly {
+
+/******************************************************************************
+ * Table class
+ ******************************************************************************/
+Table::~Table() {}
+
+int64_t Table::CalculatedChecksum() {
+  return data_->Checksum();
+}
+
+void Table::SetFont(Font* font) {
+  font_ = font;
+}
+
+Table::Table(Header* header, ReadableFontData* data)
+    : FontDataTable(data) {
+  header_ = header;
+}
+
+/******************************************************************************
+ * Table::Builder class
+ ******************************************************************************/
+Table::Builder::~Builder() {
+  header_.Release();
+}
+
+void Table::Builder::NotifyPostTableBuild(FontDataTable* table) {
+  if (model_changed() || data_changed()) {
+    Table* derived_table = down_cast<Table*>(table);
+    derived_table->header_ = new Header(header()->tag(),
+                                        derived_table->DataLength());
+  }
+}
+
+CALLER_ATTACH
+Table::Builder* Table::Builder::GetBuilder(Header* header,
+                                           WritableFontData* table_data) {
+  int32_t tag = header->tag();
+  Table::Builder* builder_raw = NULL;
+
+  // Note: Tables are commented out when they are not used/ported.
+  // TODO(arthurhsu): IMPLEMENT: finish tables that are not ported.
+  if (tag == Tag::head) {
+    builder_raw = static_cast<Table::Builder*>(
+        FontHeaderTable::Builder::CreateBuilder(header, table_data));
+#if defined (SFNTLY_EXPERIMENTAL)
+  } else if (tag == Tag::cmap) {
+    builder_raw = static_cast<Table::Builder*>(
+        CMapTable::Builder::CreateBuilder(header, table_data));
+#endif  // SFNTLY_EXPERIMENTAL
+  } else if (tag == Tag::hhea) {
+    builder_raw = static_cast<Table::Builder*>(
+        HorizontalHeaderTable::Builder::CreateBuilder(header, table_data));
+  } else if (tag == Tag::hmtx) {
+    builder_raw = static_cast<Table::Builder*>(
+        HorizontalMetricsTable::Builder::CreateBuilder(header, table_data));
+  } else if (tag == Tag::maxp) {
+    builder_raw = static_cast<Table::Builder*>(
+        MaximumProfileTable::Builder::CreateBuilder(header, table_data));
+  } else if (tag == Tag::name) {
+    builder_raw = static_cast<Table::Builder*>(
+        NameTable::Builder::CreateBuilder(header, table_data));
+  } else if (tag == Tag::OS_2) {
+    builder_raw = static_cast<Table::Builder*>(
+        OS2Table::Builder::CreateBuilder(header, table_data));
+  }/* else if (tag == Tag::PostScript) {
+    builder_raw = static_cast<Table::Builder*>(
+        PostScriptTable::Builder::CreateBuilder(header, table_data));
+  } else if (tag == Tag::cvt) {
+    builder_raw = static_cast<Table::Builder*>(
+        ControlValueTable::Builder::CreateBuilder(header, table_data));
+  }*/ else if (tag == Tag::glyf) {
+    builder_raw = static_cast<Table::Builder*>(
+        GlyphTable::Builder::CreateBuilder(header, table_data));
+  } else if (tag == Tag::loca) {
+    builder_raw = static_cast<Table::Builder*>(
+        LocaTable::Builder::CreateBuilder(header, table_data));
+  } else if (tag == Tag::EBDT || tag == Tag::bdat) {
+    builder_raw = static_cast<Table::Builder*>(
+        EbdtTable::Builder::CreateBuilder(header, table_data));
+  } else if (tag == Tag::EBLC || tag == Tag::bloc) {
+    builder_raw = static_cast<Table::Builder*>(
+        EblcTable::Builder::CreateBuilder(header, table_data));
+  } else if (tag == Tag::EBSC) {
+    builder_raw = static_cast<Table::Builder*>(
+        EbscTable::Builder::CreateBuilder(header, table_data));
+  } /* else if (tag == Tag::prep) {
+    builder_raw = static_cast<Table::Builder*>(
+        ControlProgramTable::Builder::CreateBuilder(header, table_data));
+  }*/ else if (tag == Tag::bhed) {
+    builder_raw = static_cast<Table::Builder*>(
+        FontHeaderTable::Builder::CreateBuilder(header, table_data));
+#if defined (SFNTLY_EXPERIMENTAL)
+  } else if (tag == Tag::hdmx) {
+    builder_raw = static_cast<Table::Builder*>(
+        HorizontalDeviceMetricsTable::Builder::CreateBuilder(header,
+                                                             table_data));
+#endif  // SFNTLY_EXPERIMENTAL
+  } else {
+    builder_raw = static_cast<Table::Builder*>(
+        GenericTableBuilder::CreateBuilder(header, table_data));
+  }
+
+  return builder_raw;
+}
+
+Table::Builder::Builder(Header* header, WritableFontData* data)
+    : FontDataTable::Builder(data) {
+  header_ = header;
+}
+
+Table::Builder::Builder(Header* header, ReadableFontData* data)
+    : FontDataTable::Builder(data) {
+  header_ = header;
+}
+
+Table::Builder::Builder(Header* header) {
+  header_ = header;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/table.h b/cpp/src/sfntly/table/table.h
new file mode 100644
index 0000000..6ebc22d
--- /dev/null
+++ b/cpp/src/sfntly/table/table.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_
+
+#include <set>
+#include <map>
+#include <vector>
+#include <utility>
+
+#include "sfntly/port/type.h"
+#include "sfntly/table/font_data_table.h"
+#include "sfntly/table/header.h"
+
+namespace sfntly {
+class Font;
+
+// A concrete implementation of a root level table in the font. This is the base
+// class used for all specific table implementations and is used as the generic
+// table for all tables which have no specific implementations.
+class Table : public FontDataTable {
+ public:
+  // Note: original version is Builder<T extends Table>
+  //       C++ template is not designed that way so plain old inheritance is
+  //       chosen.
+  class Builder : public FontDataTable::Builder {
+   public:
+    virtual ~Builder();
+    virtual Header* header() { return header_; }
+    virtual void NotifyPostTableBuild(FontDataTable* table);
+
+    // Get a builder for the table type specified by the data in the header.
+    // @param header the header for the table
+    // @param tableData the data to be used to build the table from
+    // @return builder for the table specified
+    static CALLER_ATTACH Builder* GetBuilder(Header* header,
+                                             WritableFontData* table_data);
+
+    // UNIMPLEMENTED: toString()
+
+   protected:
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    Builder(Header* header);
+
+   private:
+    Ptr<Header> header_;
+  };
+
+  // Note: GenericTableBuilder moved to table_based_table_builder.h to avoid
+  //       circular inclusion.
+
+  virtual ~Table();
+
+  // Get the calculated checksum for the data in the table.
+  virtual int64_t CalculatedChecksum();
+
+  // Get the header for the table.
+  virtual Header* header()          { return header_; }
+
+  // Get the tag for the table from the record header.
+  virtual int32_t header_tag()      { return header_->tag(); }
+
+  // Get the offset for the table from the record header.
+  virtual int32_t header_offset()   { return header_->offset(); }
+
+  // Get the length of the table from the record header.
+  virtual int32_t header_length()   { return header_->length(); }
+
+  // Get the checksum for the table from the record header.
+  virtual int64_t header_checksum() { return header_->checksum(); }
+
+  // UNIMPLEMENTED: toString()
+
+  virtual void SetFont(Font* font);
+
+ protected:
+  Table(Header* header, ReadableFontData* data);
+
+ private:
+  Ptr<Header> header_;
+  Ptr<Font> font_;
+};
+
+// C++ port only
+class GenericTable : public Table, public RefCounted<GenericTable> {
+ public:
+  GenericTable(Header* header, ReadableFontData* data) : Table(header, data) {}
+  virtual ~GenericTable() {}
+};
+
+typedef Ptr<Table> TablePtr;
+typedef std::vector<HeaderPtr> TableHeaderList;
+typedef Ptr<Table::Builder> TableBuilderPtr;
+typedef std::map<int32_t, TablePtr> TableMap;
+typedef std::pair<int32_t, TablePtr> TableMapEntry;
+
+typedef std::map<HeaderPtr, WritableFontDataPtr> DataBlockMap;
+typedef std::pair<HeaderPtr, WritableFontDataPtr> DataBlockEntry;
+typedef std::map<int32_t, TableBuilderPtr> TableBuilderMap;
+typedef std::pair<int32_t, TableBuilderPtr> TableBuilderEntry;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_H_
diff --git a/cpp/src/sfntly/table/table_based_table_builder.cc b/cpp/src/sfntly/table/table_based_table_builder.cc
new file mode 100644
index 0000000..b505704
--- /dev/null
+++ b/cpp/src/sfntly/table/table_based_table_builder.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/table_based_table_builder.h"
+
+namespace sfntly {
+
+/******************************************************************************
+ * TableBasedTableBuilder class
+ ******************************************************************************/
+TableBasedTableBuilder::~TableBasedTableBuilder() {}
+
+int32_t TableBasedTableBuilder::SubSerialize(WritableFontData* data) {
+  UNREFERENCED_PARAMETER(data);
+  return 0;
+}
+
+bool TableBasedTableBuilder::SubReadyToSerialize() {
+  return false;
+}
+
+int32_t TableBasedTableBuilder::SubDataSizeToSerialize() {
+  return 0;
+}
+
+void TableBasedTableBuilder::SubDataSet() {
+  table_ = NULL;
+}
+
+CALLER_ATTACH FontDataTable* TableBasedTableBuilder::Build() {
+  FontDataTablePtr table = static_cast<FontDataTable*>(GetTable());
+  return table.Detach();
+}
+
+TableBasedTableBuilder::TableBasedTableBuilder(Header* header,
+                                               WritableFontData* data)
+    : Table::Builder(header, data) {
+}
+
+TableBasedTableBuilder::TableBasedTableBuilder(Header* header,
+                                               ReadableFontData* data)
+    : Table::Builder(header, data) {
+}
+
+TableBasedTableBuilder::TableBasedTableBuilder(Header* header)
+    : Table::Builder(header) {
+}
+
+Table* TableBasedTableBuilder::GetTable() {
+  if (table_ == NULL) {
+    table_.Attach(down_cast<Table*>(SubBuildTable(InternalReadData())));
+  }
+  return table_;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/table_based_table_builder.h b/cpp/src/sfntly/table/table_based_table_builder.h
new file mode 100644
index 0000000..d88eefd
--- /dev/null
+++ b/cpp/src/sfntly/table/table_based_table_builder.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_
+
+#include "sfntly/table/table.h"
+
+namespace sfntly {
+
+class TableBasedTableBuilder : public Table::Builder {
+ public:
+  virtual ~TableBasedTableBuilder();
+
+  virtual int32_t SubSerialize(WritableFontData* new_data);
+  virtual bool SubReadyToSerialize();
+  virtual int32_t SubDataSizeToSerialize();
+  virtual void SubDataSet();
+  virtual CALLER_ATTACH FontDataTable* Build();
+
+ protected:
+  TableBasedTableBuilder(Header* header, WritableFontData* data);
+  TableBasedTableBuilder(Header* header, ReadableFontData* data);
+  explicit TableBasedTableBuilder(Header* header);
+
+  // C++ port: renamed table() to GetTable()
+  virtual Table* GetTable();
+
+  // TODO(arthurhsu): style guide violation: protected member, need refactor
+  TablePtr table_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_TABLE_BASED_TABLE_BUILDER_H_
diff --git a/cpp/src/sfntly/table/truetype/glyph_table.cc b/cpp/src/sfntly/table/truetype/glyph_table.cc
new file mode 100644
index 0000000..f38fac5
--- /dev/null
+++ b/cpp/src/sfntly/table/truetype/glyph_table.cc
@@ -0,0 +1,679 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/truetype/glyph_table.h"
+
+#include <stdlib.h>
+
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+/******************************************************************************
+ * Constants
+ ******************************************************************************/
+const int32_t GlyphTable::SimpleGlyph::kFLAG_ONCURVE = 1;
+const int32_t GlyphTable::SimpleGlyph::kFLAG_XSHORT = 1 << 1;
+const int32_t GlyphTable::SimpleGlyph::kFLAG_YSHORT = 1 << 2;
+const int32_t GlyphTable::SimpleGlyph::kFLAG_REPEAT = 1 << 3;
+const int32_t GlyphTable::SimpleGlyph::kFLAG_XREPEATSIGN = 1 << 4;
+const int32_t GlyphTable::SimpleGlyph::kFLAG_YREPEATSIGN = 1 << 5;
+
+const int32_t GlyphTable::CompositeGlyph::kFLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_ARGS_ARE_XY_VALUES = 1 << 1;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_ROUND_XY_TO_GRID = 1 << 2;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_SCALE = 1 << 3;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_RESERVED = 1 << 4;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_MORE_COMPONENTS = 1 << 5;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_USE_MY_METRICS = 1 << 9;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_OVERLAP_COMPOUND = 1 << 10;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_SCALED_COMPONENT_OFFSET = 1 << 11;
+const int32_t GlyphTable::CompositeGlyph::kFLAG_UNSCALED_COMPONENT_OFFSET = 1 << 12;
+
+/******************************************************************************
+ * GlyphTable class
+ ******************************************************************************/
+GlyphTable::~GlyphTable() {
+}
+
+GlyphTable::Glyph* GlyphTable::GetGlyph(int32_t offset, int32_t length) {
+  return GlyphTable::Glyph::GetGlyph(this, this->data_, offset, length);
+}
+
+GlyphTable::GlyphTable(Header* header, ReadableFontData* data)
+    : SubTableContainerTable(header, data) {
+}
+
+/******************************************************************************
+ * GlyphTable::Builder class
+ ******************************************************************************/
+GlyphTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : SubTableContainerTable::Builder(header, data) {
+}
+
+GlyphTable::Builder::~Builder() {
+}
+
+void GlyphTable::Builder::SetLoca(const IntegerList& loca) {
+  loca_ = loca;
+  set_model_changed(false);
+  glyph_builders_.clear();
+}
+
+void GlyphTable::Builder::GenerateLocaList(IntegerList* locas) {
+  assert(locas);
+  GlyphBuilderList* glyph_builders = GetGlyphBuilders();
+  locas->push_back(0);
+  if (glyph_builders->size() == 0) {
+    locas->push_back(0);
+  } else {
+    int32_t total = 0;
+    for (GlyphBuilderList::iterator b = glyph_builders->begin(),
+                                    b_end = glyph_builders->end();
+                                    b != b_end; ++b) {
+      int32_t size = (*b)->SubDataSizeToSerialize();
+      locas->push_back(total + size);
+      total += size;
+    }
+  }
+}
+
+CALLER_ATTACH GlyphTable::Builder*
+    GlyphTable::Builder::CreateBuilder(Header* header, WritableFontData* data) {
+  Ptr<GlyphTable::Builder> builder;
+  builder = new GlyphTable::Builder(header, data);
+  return builder.Detach();
+}
+
+GlyphTable::GlyphBuilderList* GlyphTable::Builder::GlyphBuilders() {
+  return GetGlyphBuilders();
+}
+
+void GlyphTable::Builder::SetGlyphBuilders(GlyphBuilderList* glyph_builders) {
+  glyph_builders_ = *glyph_builders;
+  set_model_changed();
+}
+
+CALLER_ATTACH GlyphTable::Glyph::Builder*
+    GlyphTable::Builder::GlyphBuilder(ReadableFontData* data) {
+  return Glyph::Builder::GetBuilder(this, data);
+}
+
+CALLER_ATTACH FontDataTable*
+    GlyphTable::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table = new GlyphTable(header(), data);
+  return table.Detach();
+}
+
+void GlyphTable::Builder::SubDataSet() {
+  glyph_builders_.clear();
+  set_model_changed(false);
+}
+
+int32_t GlyphTable::Builder::SubDataSizeToSerialize() {
+  if (glyph_builders_.empty())
+    return 0;
+
+  bool variable = false;
+  int32_t size = 0;
+
+  // Calculate size of each table.
+  for (GlyphBuilderList::iterator b = glyph_builders_.begin(),
+                                  end = glyph_builders_.end(); b != end; ++b) {
+      int32_t glyph_size = (*b)->SubDataSizeToSerialize();
+      size += abs(glyph_size);
+      variable |= glyph_size <= 0;
+  }
+  return variable ? -size : size;
+}
+
+bool GlyphTable::Builder::SubReadyToSerialize() {
+  return !glyph_builders_.empty();
+}
+
+int32_t GlyphTable::Builder::SubSerialize(WritableFontData* new_data) {
+  int32_t size = 0;
+  for (GlyphBuilderList::iterator b = glyph_builders_.begin(),
+                                  end = glyph_builders_.end(); b != end; ++b) {
+    FontDataPtr data;
+    data.Attach(new_data->Slice(size));
+    size += (*b)->SubSerialize(down_cast<WritableFontData*>(data.p_));
+  }
+  return size;
+}
+
+void GlyphTable::Builder::Initialize(ReadableFontData* data,
+                                     const IntegerList& loca) {
+  if (data != NULL) {
+    if (loca_.empty()) {
+      return;
+    }
+    int32_t loca_value;
+    int32_t last_loca_value = loca[0];
+    for (size_t i = 1; i < loca.size(); ++i) {
+      loca_value = loca[i];
+      GlyphBuilderPtr builder;
+      builder.Attach(
+        Glyph::Builder::GetBuilder(this,
+                                   data,
+                                   last_loca_value /*offset*/,
+                                   loca_value - last_loca_value /*length*/));
+      glyph_builders_.push_back(builder);
+      last_loca_value = loca_value;
+    }
+  }
+}
+
+GlyphTable::GlyphBuilderList* GlyphTable::Builder::GetGlyphBuilders() {
+  if (glyph_builders_.empty()) {
+    if (InternalReadData() && !loca_.empty()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IllegalStateException(
+          "Loca values not set - unable to parse glyph data.");
+#endif
+      return NULL;
+    }
+    Initialize(InternalReadData(), loca_);
+    set_model_changed();
+  }
+  return &glyph_builders_;
+}
+
+void GlyphTable::Builder::Revert() {
+  glyph_builders_.clear();
+  set_model_changed(false);
+}
+
+/******************************************************************************
+ * GlyphTable::Glyph class
+ ******************************************************************************/
+GlyphTable::Glyph::~Glyph() {}
+
+CALLER_ATTACH GlyphTable::Glyph*
+    GlyphTable::Glyph::GetGlyph(GlyphTable* table,
+                                ReadableFontData* data,
+                                int32_t offset,
+                                int32_t length) {
+  UNREFERENCED_PARAMETER(table);
+  int32_t type = GlyphType(data, offset, length);
+  GlyphPtr glyph;
+
+  ReadableFontDataPtr sliced_data;
+  sliced_data.Attach(down_cast<ReadableFontData*>(data->Slice(offset, length)));
+  if (type == GlyphType::kSimple) {
+    glyph = new SimpleGlyph(sliced_data);
+  } else {
+    glyph = new CompositeGlyph(sliced_data);
+  }
+  return glyph.Detach();
+}
+
+int32_t GlyphTable::Glyph::Padding() {
+  Initialize();
+  return SubTable::Padding();
+}
+
+int32_t GlyphTable::Glyph::GlyphType() {
+  return glyph_type_;
+}
+
+int32_t GlyphTable::Glyph::NumberOfContours() {
+  return number_of_contours_;
+}
+
+int32_t GlyphTable::Glyph::XMin() {
+  return data_->ReadShort(Offset::kXMin);
+}
+
+int32_t GlyphTable::Glyph::XMax() {
+  return data_->ReadShort(Offset::kXMax);
+}
+
+int32_t GlyphTable::Glyph::YMin() {
+  return data_->ReadShort(Offset::kYMin);
+}
+
+int32_t GlyphTable::Glyph::YMax() {
+  return data_->ReadShort(Offset::kYMax);
+}
+
+GlyphTable::Glyph::Glyph(ReadableFontData* data, int32_t glyph_type)
+    : SubTable(data),
+      glyph_type_(glyph_type) {
+  if (data_->Length() == 0) {
+    number_of_contours_ = 0;
+  } else {
+    // -1 if composite
+    number_of_contours_ = data_->ReadShort(Offset::kNumberOfContours);
+  }
+}
+
+int32_t GlyphTable::Glyph::GlyphType(ReadableFontData* data,
+                                     int32_t offset,
+                                     int32_t length) {
+  if (length == 0) {
+    return GlyphType::kSimple;
+  }
+  int32_t number_of_contours = data->ReadShort(offset);
+  if (number_of_contours >= 0) {
+    return GlyphType::kSimple;
+  }
+  return GlyphType::kComposite;
+}
+
+/******************************************************************************
+ * GlyphTable::Glyph::Builder class
+ ******************************************************************************/
+GlyphTable::Glyph::Builder::~Builder() {
+}
+
+GlyphTable::Glyph::Builder::Builder(WritableFontData* data)
+    : SubTable::Builder(data) {
+}
+
+GlyphTable::Glyph::Builder::Builder(ReadableFontData* data)
+    : SubTable::Builder(data) {
+}
+
+CALLER_ATTACH GlyphTable::Glyph::Builder*
+    GlyphTable::Glyph::Builder::GetBuilder(
+        GlyphTable::Builder* table_builder,
+        ReadableFontData* data) {
+  return GetBuilder(table_builder, data, 0, data->Length());
+}
+
+CALLER_ATTACH GlyphTable::Glyph::Builder*
+    GlyphTable::Glyph::Builder::GetBuilder(
+        GlyphTable::Builder* table_builder,
+        ReadableFontData* data,
+        int32_t offset,
+        int32_t length) {
+  UNREFERENCED_PARAMETER(table_builder);
+  int32_t type = Glyph::GlyphType(data, offset, length);
+  GlyphBuilderPtr builder;
+  ReadableFontDataPtr sliced_data;
+  sliced_data.Attach(down_cast<ReadableFontData*>(data->Slice(offset, length)));
+  if (type == GlyphType::kSimple) {
+    builder = new SimpleGlyph::SimpleGlyphBuilder(sliced_data);
+  } else {
+    builder = new CompositeGlyph::CompositeGlyphBuilder(sliced_data);
+  }
+  return builder.Detach();
+}
+
+void GlyphTable::Glyph::Builder::SubDataSet() {
+  // NOP
+}
+
+int32_t GlyphTable::Glyph::Builder::SubDataSizeToSerialize() {
+  return InternalReadData()->Length();
+}
+
+bool GlyphTable::Glyph::Builder::SubReadyToSerialize() {
+  return true;
+}
+
+int32_t GlyphTable::Glyph::Builder::SubSerialize(WritableFontData* new_data) {
+  return InternalReadData()->CopyTo(new_data);
+}
+
+/******************************************************************************
+ * GlyphTable::SimpleGlyph
+ ******************************************************************************/
+GlyphTable::SimpleGlyph::SimpleGlyph(ReadableFontData* data)
+    : GlyphTable::Glyph(data, GlyphType::kSimple), initialized_(false) {
+}
+
+GlyphTable::SimpleGlyph::~SimpleGlyph() {
+}
+
+int32_t GlyphTable::SimpleGlyph::InstructionSize() {
+  Initialize();
+  return instruction_size_;
+}
+
+CALLER_ATTACH ReadableFontData* GlyphTable::SimpleGlyph::Instructions() {
+  Initialize();
+  return down_cast<ReadableFontData*>(
+             data_->Slice(instructions_offset_, InstructionSize()));
+}
+
+int32_t GlyphTable::SimpleGlyph::NumberOfPoints(int32_t contour) {
+  Initialize();
+  if (contour >= NumberOfContours()) {
+    return 0;
+  }
+  return contour_index_[contour + 1] - contour_index_[contour];
+}
+
+int32_t GlyphTable::SimpleGlyph::XCoordinate(int32_t contour, int32_t point) {
+  Initialize();
+  return x_coordinates_[contour_index_[contour] + point];
+}
+
+int32_t GlyphTable::SimpleGlyph::YCoordinate(int32_t contour, int32_t point) {
+  Initialize();
+  return y_coordinates_[contour_index_[contour] + point];
+}
+
+bool GlyphTable::SimpleGlyph::OnCurve(int32_t contour, int32_t point) {
+  Initialize();
+  return on_curve_[contour_index_[contour] + point];
+}
+
+void GlyphTable::SimpleGlyph::Initialize() {
+  AutoLock lock(initialization_lock_);
+  if (initialized_) {
+    return;
+  }
+
+  if (ReadFontData()->Length() == 0) {
+    instruction_size_ = 0;
+    number_of_points_ = 0;
+    instructions_offset_ = 0;
+    flags_offset_ = 0;
+    x_coordinates_offset_ = 0;
+    y_coordinates_offset_ = 0;
+    return;
+  }
+
+  instruction_size_ = data_->ReadUShort(Offset::kSimpleEndPtsOfCountours +
+      NumberOfContours() * DataSize::kUSHORT);
+  instructions_offset_ = Offset::kSimpleEndPtsOfCountours +
+      (NumberOfContours() + 1) * DataSize::kUSHORT;
+  flags_offset_ = instructions_offset_ + instruction_size_ * DataSize::kBYTE;
+  number_of_points_ = ContourEndPoint(NumberOfContours() - 1) + 1;
+  x_coordinates_.resize(number_of_points_);
+  y_coordinates_.resize(number_of_points_);
+  on_curve_.resize(number_of_points_);
+  ParseData(false);
+  x_coordinates_offset_ = flags_offset_ + flag_byte_count_ * DataSize::kBYTE;
+  y_coordinates_offset_ = x_coordinates_offset_ + x_byte_count_ *
+      DataSize::kBYTE;
+  contour_index_.resize(NumberOfContours() + 1);
+  contour_index_[0] = 0;
+  for (uint32_t contour = 0; contour < contour_index_.size() - 1; ++contour) {
+    contour_index_[contour + 1] = ContourEndPoint(contour) + 1;
+  }
+  ParseData(true);
+  int32_t non_padded_data_length =
+    5 * DataSize::kSHORT +
+    (NumberOfContours() * DataSize::kUSHORT) +
+    DataSize::kUSHORT +
+    (instruction_size_ * DataSize::kBYTE) +
+    (flag_byte_count_ * DataSize::kBYTE) +
+    (x_byte_count_ * DataSize::kBYTE) +
+    (y_byte_count_ * DataSize::kBYTE);
+  set_padding(DataLength() - non_padded_data_length);
+  initialized_ = true;
+}
+
+void GlyphTable::SimpleGlyph::ParseData(bool fill_arrays) {
+  int32_t flag = 0;
+  int32_t flag_repeat = 0;
+  int32_t flag_index = 0;
+  int32_t x_byte_index = 0;
+  int32_t y_byte_index = 0;
+
+  for (int32_t point_index = 0; point_index < number_of_points_;
+       ++point_index) {
+    // get the flag for the current point
+    if (flag_repeat == 0) {
+      flag = FlagAsInt(flag_index++);
+      if ((flag & kFLAG_REPEAT) == kFLAG_REPEAT) {
+        flag_repeat = FlagAsInt(flag_index++);
+      }
+    } else {
+      flag_repeat--;
+    }
+
+    // on the curve?
+    if (fill_arrays) {
+      on_curve_[point_index] = ((flag & kFLAG_ONCURVE) == kFLAG_ONCURVE);
+    }
+    // get the x coordinate
+    if ((flag & kFLAG_XSHORT) == kFLAG_XSHORT) {
+      // single byte x coord value
+      if (fill_arrays) {
+        x_coordinates_[point_index] =
+            data_->ReadUByte(x_coordinates_offset_ + x_byte_index);
+        x_coordinates_[point_index] *=
+            ((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN) ? 1 : -1;
+      }
+      x_byte_index++;
+    } else {
+      // double byte coord value
+      if (!((flag & kFLAG_XREPEATSIGN) == kFLAG_XREPEATSIGN)) {
+        if (fill_arrays) {
+          x_coordinates_[point_index] =
+            data_->ReadShort(x_coordinates_offset_ + x_byte_index);
+        }
+        x_byte_index += 2;
+      }
+    }
+    if (fill_arrays && point_index > 0) {
+      x_coordinates_[point_index] += x_coordinates_[point_index - 1];
+    }
+
+    // get the y coordinate
+    if ((flag & kFLAG_YSHORT) == kFLAG_YSHORT) {
+      if (fill_arrays) {
+        y_coordinates_[point_index] =
+          data_->ReadUByte(y_coordinates_offset_ + y_byte_index);
+        y_coordinates_[point_index] *=
+          ((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN) ? 1 : -1;
+      }
+      y_byte_index++;
+    } else {
+      if (!((flag & kFLAG_YREPEATSIGN) == kFLAG_YREPEATSIGN)) {
+        if (fill_arrays) {
+          y_coordinates_[point_index] =
+            data_->ReadShort(y_coordinates_offset_ + y_byte_index);
+        }
+        y_byte_index += 2;
+      }
+    }
+    if (fill_arrays && point_index > 0) {
+      y_coordinates_[point_index] += y_coordinates_[point_index - 1];
+    }
+  }
+  flag_byte_count_ = flag_index;
+  x_byte_count_ = x_byte_index;
+  y_byte_count_ = y_byte_index;
+}
+
+int32_t GlyphTable::SimpleGlyph::FlagAsInt(int32_t index) {
+  return data_->ReadUByte(flags_offset_ + index * DataSize::kBYTE);
+}
+
+int32_t GlyphTable::SimpleGlyph::ContourEndPoint(int32_t contour) {
+  return data_->ReadUShort(contour * DataSize::kUSHORT +
+                           Offset::kSimpleEndPtsOfCountours);
+}
+
+/******************************************************************************
+ * GlyphTable::SimpleGlyph::Builder
+ ******************************************************************************/
+GlyphTable::SimpleGlyph::SimpleGlyphBuilder::~SimpleGlyphBuilder() {
+}
+
+GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder(
+    WritableFontData* data)
+    : Glyph::Builder(data) {
+}
+
+GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SimpleGlyphBuilder(
+    ReadableFontData* data)
+    : Glyph::Builder(data) {
+}
+
+CALLER_ATTACH FontDataTable*
+    GlyphTable::SimpleGlyph::SimpleGlyphBuilder::SubBuildTable(
+        ReadableFontData* data) {
+  FontDataTablePtr table = new SimpleGlyph(data);
+  return table.Detach();
+}
+
+/******************************************************************************
+ * GlyphTable::CompositeGlyph
+ ******************************************************************************/
+GlyphTable::CompositeGlyph::CompositeGlyph(ReadableFontData* data)
+    : GlyphTable::Glyph(data, GlyphType::kComposite),
+      instruction_size_(0),
+      instructions_offset_(0),
+      initialized_(false) {
+  Initialize();
+}
+
+GlyphTable::CompositeGlyph::~CompositeGlyph() {
+}
+
+int32_t GlyphTable::CompositeGlyph::Flags(int32_t contour) {
+  return data_->ReadUShort(contour_index_[contour]);
+}
+
+int32_t GlyphTable::CompositeGlyph::NumGlyphs() {
+  return contour_index_.size();
+}
+
+int32_t GlyphTable::CompositeGlyph::GlyphIndex(int32_t contour) {
+  return data_->ReadUShort(DataSize::kUSHORT + contour_index_[contour]);
+}
+
+int32_t GlyphTable::CompositeGlyph::Argument1(int32_t contour) {
+  int32_t index = 2 * DataSize::kUSHORT + contour_index_[contour];
+  int32_t contour_flags = Flags(contour);
+  if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) ==
+                       kFLAG_ARG_1_AND_2_ARE_WORDS) {
+    return data_->ReadUShort(index);
+  }
+  return data_->ReadByte(index);
+}
+
+int32_t GlyphTable::CompositeGlyph::Argument2(int32_t contour) {
+  int32_t index = 2 * DataSize::kUSHORT + contour_index_[contour];
+  int32_t contour_flags = Flags(contour);
+  if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) ==
+                       kFLAG_ARG_1_AND_2_ARE_WORDS) {
+    return data_->ReadUShort(index + DataSize::kUSHORT);
+  }
+  return data_->ReadByte(index + DataSize::kUSHORT);
+}
+
+int32_t GlyphTable::CompositeGlyph::TransformationSize(int32_t contour) {
+  int32_t contour_flags = Flags(contour);
+  if ((contour_flags & kFLAG_WE_HAVE_A_SCALE) == kFLAG_WE_HAVE_A_SCALE) {
+      return DataSize::kF2DOT14;
+    } else if ((contour_flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) ==
+                                kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
+      return 2 * DataSize::kF2DOT14;
+    } else if ((contour_flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) ==
+                                kFLAG_WE_HAVE_A_TWO_BY_TWO) {
+      return 4 * DataSize::kF2DOT14;
+    }
+    return 0;
+}
+
+void GlyphTable::CompositeGlyph::Transformation(int32_t contour,
+                                                ByteVector* transformation) {
+  int32_t contour_flags = Flags(contour);
+  int32_t index = contour_index_[contour] + 2 * DataSize::kUSHORT;
+  if ((contour_flags & kFLAG_ARG_1_AND_2_ARE_WORDS) ==
+                       kFLAG_ARG_1_AND_2_ARE_WORDS) {
+    index += 2 * DataSize::kSHORT;
+  } else {
+    index += 2 * DataSize::kBYTE;
+  }
+  int32_t tsize = TransformationSize(contour);
+  transformation->resize(tsize);
+  data_->ReadBytes(index, &((*transformation)[0]), 0, tsize);
+}
+
+int32_t GlyphTable::CompositeGlyph::InstructionSize() {
+  return instruction_size_;
+}
+
+CALLER_ATTACH ReadableFontData* GlyphTable::CompositeGlyph::Instructions() {
+  return down_cast<ReadableFontData*>(
+             data_->Slice(instructions_offset_, InstructionSize()));
+}
+
+void GlyphTable::CompositeGlyph::Initialize() {
+  AutoLock lock(initialization_lock_);
+  if (initialized_) {
+    return;
+  }
+
+  int32_t index = 5 * DataSize::kUSHORT;
+  int32_t flags = kFLAG_MORE_COMPONENTS;
+
+  while ((flags & kFLAG_MORE_COMPONENTS) == kFLAG_MORE_COMPONENTS) {
+    contour_index_.push_back(index);
+    flags = data_->ReadUShort(index);
+    index += 2 * DataSize::kUSHORT;  // flags and glyphIndex
+    if ((flags & kFLAG_ARG_1_AND_2_ARE_WORDS) == kFLAG_ARG_1_AND_2_ARE_WORDS) {
+      index += 2 * DataSize::kSHORT;
+    } else {
+      index += 2 * DataSize::kBYTE;
+    }
+    if ((flags & kFLAG_WE_HAVE_A_SCALE) == kFLAG_WE_HAVE_A_SCALE) {
+      index += DataSize::kF2DOT14;
+    } else if ((flags & kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) ==
+                        kFLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
+      index += 2 * DataSize::kF2DOT14;
+    } else if ((flags & kFLAG_WE_HAVE_A_TWO_BY_TWO) ==
+                        kFLAG_WE_HAVE_A_TWO_BY_TWO) {
+      index += 4 * DataSize::kF2DOT14;
+    }
+    int32_t non_padded_data_length = index;
+    if ((flags & kFLAG_WE_HAVE_INSTRUCTIONS) == kFLAG_WE_HAVE_INSTRUCTIONS) {
+      instruction_size_ = data_->ReadUShort(index);
+      index += DataSize::kUSHORT;
+      instructions_offset_ = index;
+      non_padded_data_length = index + (instruction_size_ * DataSize::kBYTE);
+    }
+    set_padding(DataLength() - non_padded_data_length);
+  }
+
+  initialized_ = true;
+}
+
+/******************************************************************************
+ * GlyphTable::CompositeGlyph::Builder
+ ******************************************************************************/
+GlyphTable::CompositeGlyph::CompositeGlyphBuilder::~CompositeGlyphBuilder() {
+}
+
+GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder(
+    WritableFontData* data)
+    : Glyph::Builder(data) {
+}
+
+GlyphTable::CompositeGlyph::CompositeGlyphBuilder::CompositeGlyphBuilder(
+    ReadableFontData* data)
+    : Glyph::Builder(data) {
+}
+
+CALLER_ATTACH FontDataTable*
+    GlyphTable::CompositeGlyph::CompositeGlyphBuilder::SubBuildTable(
+        ReadableFontData* data) {
+  FontDataTablePtr table = new CompositeGlyph(data);
+  return table.Detach();
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/truetype/glyph_table.h b/cpp/src/sfntly/table/truetype/glyph_table.h
new file mode 100644
index 0000000..4ffddda
--- /dev/null
+++ b/cpp/src/sfntly/table/truetype/glyph_table.h
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_
+
+#include <vector>
+
+#include "sfntly/table/table.h"
+#include "sfntly/table/subtable.h"
+#include "sfntly/table/subtable_container_table.h"
+
+namespace sfntly {
+
+struct GlyphType {
+  enum {
+    kSimple = 0,
+    kComposite = 1
+  };
+};
+
+class GlyphTable : public SubTableContainerTable,
+                   public RefCounted<GlyphTable> {
+ public:
+  class Builder;
+  class Glyph : public SubTable {
+   public:
+    // Note: Contour is an empty class for the version ported
+    class Contour {
+     protected:
+      Contour() {}
+      virtual ~Contour() {}
+    };
+
+    class Builder : public SubTable::Builder {
+     public:
+      virtual ~Builder();
+
+     protected:
+      // Incoming table_builder is GlyphTable::Builder*.
+      // Note: constructor refactored in C++ to avoid heavy lifting.
+      //       caller need to do data->Slice(offset, length) beforehand.
+      explicit Builder(WritableFontData* data);
+      explicit Builder(ReadableFontData* data);
+
+      static CALLER_ATTACH Builder*
+          GetBuilder(GlyphTable::Builder* table_builder,
+                     ReadableFontData* data);
+      static CALLER_ATTACH Builder*
+          GetBuilder(GlyphTable::Builder* table_builder,
+                     ReadableFontData* data,
+                     int32_t offset,
+                     int32_t length);
+      virtual void SubDataSet();
+      virtual int32_t SubDataSizeToSerialize();
+      virtual bool SubReadyToSerialize();
+      virtual int32_t SubSerialize(WritableFontData* new_data);
+
+     private:
+      friend class GlyphTable::Builder;
+    };
+
+    virtual ~Glyph();
+    static CALLER_ATTACH Glyph* GetGlyph(GlyphTable* table,
+                                         ReadableFontData* data,
+                                         int32_t offset,
+                                         int32_t length);
+
+    virtual int32_t Padding();
+    virtual int32_t GlyphType();
+    virtual int32_t NumberOfContours();
+    virtual int32_t XMin();
+    virtual int32_t XMax();
+    virtual int32_t YMin();
+    virtual int32_t YMax();
+
+    virtual int32_t InstructionSize() = 0;
+    virtual ReadableFontData* Instructions() = 0;
+
+   protected:
+    // Note: constructor refactored in C++ to avoid heavy lifting.
+    //       caller need to do data->Slice(offset, length) beforehand.
+    Glyph(ReadableFontData* data, int32_t glyph_type);
+    virtual void Initialize() = 0;
+    // Note: Derived class to define initialization_lock_.
+
+   private:
+    static int32_t GlyphType(ReadableFontData* data,
+                             int32_t offset,
+                             int32_t length);
+
+    int32_t glyph_type_;
+    int32_t number_of_contours_;
+  };  // class GlyphTable::Glyph
+  typedef Ptr<GlyphTable::Glyph::Builder> GlyphBuilderPtr;
+  typedef std::vector<GlyphBuilderPtr> GlyphBuilderList;
+
+  class Builder : public SubTableContainerTable::Builder,
+                  public RefCounted<GlyphTable::Builder> {
+   public:
+    // Note: Constructor scope altered to public for base class to instantiate.
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+
+    virtual void SetLoca(const IntegerList& loca);
+    virtual void GenerateLocaList(IntegerList* locas);
+
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+
+    // Gets the List of glyph builders for the glyph table builder. These may be
+    // manipulated in any way by the caller and the changes will be reflected in
+    // the final glyph table produced.
+    // If there is no current data for the glyph builder or the glyph builders
+    // have not been previously set then this will return an empty glyph builder
+    // List. If there is current data (i.e. data read from an existing font) and
+    // the <code>loca</code> list has not been set or is null, empty, or
+    // invalid, then an empty glyph builder List will be returned.
+    GlyphBuilderList* GlyphBuilders();
+
+    // Replace the internal glyph builders with the one provided. The provided
+    // list and all contained objects belong to this builder.
+    // This call is only required if the entire set of glyphs in the glyph
+    // table builder are being replaced. If the glyph builder list provided from
+    // the GlyphTable.Builder::GlyphBuilders() is being used and modified
+    // then those changes will already be reflected in the glyph table builder.
+    void SetGlyphBuilders(GlyphBuilderList* glyph_builders);
+
+    // Glyph builder factories
+    CALLER_ATTACH Glyph::Builder* GlyphBuilder(ReadableFontData* data);
+
+   protected:  // internal API for building
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+   private:
+    void Initialize(ReadableFontData* data, const IntegerList& loca);
+    GlyphBuilderList* GetGlyphBuilders();
+    void Revert();
+
+    GlyphBuilderList glyph_builders_;
+    IntegerList loca_;
+  };
+
+  class SimpleGlyph : public Glyph, public RefCounted<SimpleGlyph> {
+   public:
+    static const int32_t kFLAG_ONCURVE;
+    static const int32_t kFLAG_XSHORT;
+    static const int32_t kFLAG_YSHORT;
+    static const int32_t kFLAG_REPEAT;
+    static const int32_t kFLAG_XREPEATSIGN;
+    static const int32_t kFLAG_YREPEATSIGN;
+
+    class SimpleContour : public Glyph::Contour {
+     protected:
+      SimpleContour() {}
+      virtual ~SimpleContour() {}
+    };
+
+    class SimpleGlyphBuilder : public Glyph::Builder,
+                               public RefCounted<SimpleGlyphBuilder> {
+     public:
+      virtual ~SimpleGlyphBuilder();
+
+     protected:
+      // Note: constructor refactored in C++ to avoid heavy lifting.
+      //       caller need to do data->Slice(offset, length) beforehand.
+      explicit SimpleGlyphBuilder(WritableFontData* data);
+      explicit SimpleGlyphBuilder(ReadableFontData* data);
+      virtual CALLER_ATTACH FontDataTable*
+          SubBuildTable(ReadableFontData* data);
+
+     private:
+      friend class Glyph::Builder;
+    };
+
+    // Note: constructor refactored in C++ to avoid heavy lifting.
+    //       caller need to do data->Slice(offset, length) beforehand.
+    explicit SimpleGlyph(ReadableFontData* data);
+    virtual ~SimpleGlyph();
+
+    virtual int32_t InstructionSize();
+    virtual CALLER_ATTACH ReadableFontData* Instructions();
+    virtual void Initialize();
+
+    int32_t NumberOfPoints(int32_t contour);
+    int32_t XCoordinate(int32_t contour, int32_t point);
+    int32_t YCoordinate(int32_t contour, int32_t point);
+    bool OnCurve(int32_t contour, int32_t point);
+
+   private:
+    void ParseData(bool fill_arrays);
+    int32_t FlagAsInt(int32_t index);
+    int32_t ContourEndPoint(int32_t contour);
+
+    bool initialized_;
+    Lock initialization_lock_;
+    int32_t instruction_size_;
+    int32_t number_of_points_;
+
+    // start offsets of the arrays
+    int32_t instructions_offset_;
+    int32_t flags_offset_;
+    int32_t x_coordinates_offset_;
+    int32_t y_coordinates_offset_;
+
+    int32_t flag_byte_count_;
+    int32_t x_byte_count_;
+    int32_t y_byte_count_;
+
+    IntegerList x_coordinates_;
+    IntegerList y_coordinates_;
+    std::vector<bool> on_curve_;
+    IntegerList contour_index_;
+  };
+
+  class CompositeGlyph : public Glyph, public RefCounted<CompositeGlyph> {
+   public:
+    static const int32_t kFLAG_ARG_1_AND_2_ARE_WORDS;
+    static const int32_t kFLAG_ARGS_ARE_XY_VALUES;
+    static const int32_t kFLAG_ROUND_XY_TO_GRID;
+    static const int32_t kFLAG_WE_HAVE_A_SCALE;
+    static const int32_t kFLAG_RESERVED;
+    static const int32_t kFLAG_MORE_COMPONENTS;
+    static const int32_t kFLAG_WE_HAVE_AN_X_AND_Y_SCALE;
+    static const int32_t kFLAG_WE_HAVE_A_TWO_BY_TWO;
+    static const int32_t kFLAG_WE_HAVE_INSTRUCTIONS;
+    static const int32_t kFLAG_USE_MY_METRICS;
+    static const int32_t kFLAG_OVERLAP_COMPOUND;
+    static const int32_t kFLAG_SCALED_COMPONENT_OFFSET;
+    static const int32_t kFLAG_UNSCALED_COMPONENT_OFFSET;
+
+    class CompositeGlyphBuilder : public Glyph::Builder,
+                                  public RefCounted<CompositeGlyphBuilder> {
+     public:
+      virtual ~CompositeGlyphBuilder();
+
+     protected:
+      // Note: constructor refactored in C++ to avoid heavy lifting.
+      //       caller need to do data->Slice(offset, length) beforehand.
+      explicit CompositeGlyphBuilder(WritableFontData* data);
+      explicit CompositeGlyphBuilder(ReadableFontData* data);
+
+      virtual CALLER_ATTACH FontDataTable*
+          SubBuildTable(ReadableFontData* data);
+
+     private:
+      friend class Glyph::Builder;
+    };
+
+    // Note: constructor refactored in C++ to avoid heavy lifting.
+    //       caller need to do data->Slice(offset, length) beforehand.
+    explicit CompositeGlyph(ReadableFontData* data);
+    virtual ~CompositeGlyph();
+
+    int32_t Flags(int32_t contour);
+    int32_t NumGlyphs();
+    int32_t GlyphIndex(int32_t contour);
+    int32_t Argument1(int32_t contour);
+    int32_t Argument2(int32_t contour);
+    int32_t TransformationSize(int32_t contour);
+    void Transformation(int32_t contour, ByteVector* transformation);
+    virtual int32_t InstructionSize();
+    virtual CALLER_ATTACH ReadableFontData* Instructions();
+
+   protected:
+    virtual void Initialize();
+
+   private:
+    IntegerList contour_index_;
+    int32_t instruction_size_;
+    int32_t instructions_offset_;
+    bool initialized_;
+    Lock initialization_lock_;
+  };
+
+  virtual ~GlyphTable();
+
+  // C++ port: rename glyph() to GetGlyph().
+  Glyph* GetGlyph(int32_t offset, int32_t length);
+
+ private:
+  struct Offset {
+    enum {
+      // header
+      kNumberOfContours = 0,
+      kXMin = 2,
+      kYMin = 4,
+      kXMax = 6,
+      kYMax = 8,
+
+      // Simple Glyph Description
+      kSimpleEndPtsOfCountours = 10,
+      // offset from the end of the contours array
+      kSimpleInstructionLength = 0,
+      kSimpleInstructions = 2,
+      // flags
+      // xCoordinates
+      // yCoordinates
+
+      // Composite Glyph Description
+      kCompositeFlags = 0,
+      kCompositeGyphIndexWithoutFlag = 0,
+      kCompositeGlyphIndexWithFlag = 2,
+    };
+  };
+
+  GlyphTable(Header* header, ReadableFontData* data);
+};
+typedef Ptr<GlyphTable> GlyphTablePtr;
+typedef Ptr<GlyphTable::Builder> GlyphTableBuilderPtr;
+typedef std::vector<GlyphTableBuilderPtr> GlyphTableBuilderList;
+typedef Ptr<GlyphTable::Glyph> GlyphPtr;
+typedef Ptr<GlyphTable::Glyph::Builder> GlyphBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_GLYPH_TABLE_H_
diff --git a/cpp/src/sfntly/table/truetype/loca_table.cc b/cpp/src/sfntly/table/truetype/loca_table.cc
new file mode 100644
index 0000000..c692155
--- /dev/null
+++ b/cpp/src/sfntly/table/truetype/loca_table.cc
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/table/truetype/loca_table.h"
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+/******************************************************************************
+ * LocaTable class
+ ******************************************************************************/
+LocaTable::~LocaTable() {}
+
+int32_t LocaTable::GlyphOffset(int32_t glyph_id) {
+  if (glyph_id < 0 || glyph_id >= num_glyphs_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException("Glyph ID is out of bounds.");
+#endif
+    return 0;
+  }
+  return Loca(glyph_id);
+}
+
+int32_t LocaTable::GlyphLength(int32_t glyph_id) {
+  if (glyph_id < 0 || glyph_id >= num_glyphs_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException("Glyph ID is out of bounds.");
+#endif
+    return 0;
+  }
+  return Loca(glyph_id + 1) - Loca(glyph_id);
+}
+
+int32_t LocaTable::NumLocas() {
+  return num_glyphs_ + 1;
+}
+
+int32_t LocaTable::Loca(int32_t index) {
+  if (index > num_glyphs_) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundException();
+#endif
+    return 0;
+  }
+  if (format_version_ == IndexToLocFormat::kShortOffset) {
+    return 2 * data_->ReadUShort(index * DataSize::kUSHORT);
+  }
+  return data_->ReadULongAsInt(index * DataSize::kULONG);
+}
+
+LocaTable::LocaTable(Header* header,
+                     ReadableFontData* data,
+                     int32_t format_version,
+                     int32_t num_glyphs)
+    : Table(header, data),
+      format_version_(format_version),
+      num_glyphs_(num_glyphs) {
+}
+
+/******************************************************************************
+ * LocaTable::Iterator class
+ ******************************************************************************/
+LocaTable::LocaIterator::LocaIterator(LocaTable* table)
+    : PODIterator<int32_t, LocaTable>(table), index_(-1) {
+}
+
+bool LocaTable::LocaIterator::HasNext() {
+  return index_ <= container()->num_glyphs_;
+}
+
+int32_t LocaTable::LocaIterator::Next() {
+  return container()->Loca(index_++);
+}
+
+/******************************************************************************
+ * LocaTable::Builder class
+ ******************************************************************************/
+LocaTable::Builder::Builder(Header* header, WritableFontData* data)
+    : Table::Builder(header, data),
+      format_version_(IndexToLocFormat::kLongOffset),
+      num_glyphs_(-1) {
+}
+
+LocaTable::Builder::Builder(Header* header, ReadableFontData* data)
+    : Table::Builder(header, data),
+      format_version_(IndexToLocFormat::kLongOffset),
+      num_glyphs_(-1) {
+}
+
+LocaTable::Builder::~Builder() {}
+
+CALLER_ATTACH
+LocaTable::Builder* LocaTable::Builder::CreateBuilder(Header* header,
+                                                      WritableFontData* data) {
+  Ptr<LocaTable::Builder> builder;
+  builder = new LocaTable::Builder(header, data);
+  return builder.Detach();
+}
+
+IntegerList* LocaTable::Builder::LocaList() {
+  return GetLocaList();
+}
+
+void LocaTable::Builder::SetLocaList(IntegerList* list) {
+  loca_.clear();
+  if (list) {
+    loca_ = *list;
+    set_model_changed();
+  }
+}
+
+int32_t LocaTable::Builder::GlyphOffset(int32_t glyph_id) {
+  if (CheckGlyphRange(glyph_id) == -1) {
+    return 0;
+  }
+  return GetLocaList()->at(glyph_id);
+}
+
+int32_t LocaTable::Builder::GlyphLength(int32_t glyph_id) {
+  if (CheckGlyphRange(glyph_id) == -1) {
+    return 0;
+  }
+  return GetLocaList()->at(glyph_id + 1) - GetLocaList()->at(glyph_id);
+}
+
+void LocaTable::Builder::SetNumGlyphs(int32_t num_glyphs) {
+  num_glyphs_ = num_glyphs;
+}
+
+int32_t LocaTable::Builder::NumGlyphs() {
+  return LastGlyphIndex() - 1;
+}
+
+void LocaTable::Builder::Revert() {
+  loca_.clear();
+  set_model_changed(false);
+}
+
+int32_t LocaTable::Builder::NumLocas() {
+  return GetLocaList()->size();
+}
+
+int32_t LocaTable::Builder::Loca(int32_t index) {
+  return GetLocaList()->at(index);
+}
+
+CALLER_ATTACH
+FontDataTable* LocaTable::Builder::SubBuildTable(ReadableFontData* data) {
+  FontDataTablePtr table =
+      new LocaTable(header(), data, format_version_, num_glyphs_);
+  return table.Detach();
+}
+
+void LocaTable::Builder::SubDataSet() {
+  Initialize(InternalReadData());
+}
+
+int32_t LocaTable::Builder::SubDataSizeToSerialize() {
+  if (loca_.empty()) {
+    return 0;
+  }
+  if (format_version_ == IndexToLocFormat::kLongOffset) {
+    return loca_.size() * DataSize::kULONG;
+  }
+  return loca_.size() * DataSize::kUSHORT;
+}
+
+bool LocaTable::Builder::SubReadyToSerialize() {
+  return !loca_.empty();
+}
+
+int32_t LocaTable::Builder::SubSerialize(WritableFontData* new_data) {
+  int32_t size = 0;
+  for (IntegerList::iterator l = loca_.begin(), end = loca_.end();
+                             l != end; ++l) {
+    if (format_version_ == IndexToLocFormat::kLongOffset) {
+      size += new_data->WriteULong(size, *l);
+    } else {
+      size += new_data->WriteUShort(size, *l / 2);
+    }
+  }
+  num_glyphs_ = loca_.size() - 1;
+  return size;
+}
+
+void LocaTable::Builder::Initialize(ReadableFontData* data) {
+  ClearLoca(false);
+  if (data) {
+    if (NumGlyphs() < 0) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+      throw IllegalStateException("numglyphs not set on LocaTable Builder.");
+#endif
+      return;
+    }
+    LocaTablePtr table =
+        new LocaTable(header(), data, format_version_, num_glyphs_);
+    Ptr<LocaTable::LocaIterator> loca_iter =
+        new LocaTable::LocaIterator(table);
+    while (loca_iter->HasNext()) {
+      loca_.push_back(loca_iter->Next());
+    }
+  }
+}
+
+int32_t LocaTable::Builder::CheckGlyphRange(int32_t glyph_id) {
+  if (glyph_id < 0 || glyph_id > LastGlyphIndex()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw IndexOutOfBoundsException("Glyph ID is outside of the allowed range");
+#endif
+    return -1;
+  }
+  return glyph_id;
+}
+
+int32_t LocaTable::Builder::LastGlyphIndex() {
+  return !loca_.empty() ? loca_.size() - 2 : num_glyphs_ - 1;
+}
+
+IntegerList* LocaTable::Builder::GetLocaList() {
+  if (loca_.empty()) {
+    Initialize(InternalReadData());
+    set_model_changed();
+  }
+  return &loca_;
+}
+
+void LocaTable::Builder::ClearLoca(bool nullify) {
+  // Note: in C++ port, nullify is not used at all.
+  UNREFERENCED_PARAMETER(nullify);
+  loca_.clear();
+  set_model_changed(false);
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/table/truetype/loca_table.h b/cpp/src/sfntly/table/truetype/loca_table.h
new file mode 100644
index 0000000..67c5749
--- /dev/null
+++ b/cpp/src/sfntly/table/truetype/loca_table.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_
+
+#include "sfntly/port/java_iterator.h"
+#include "sfntly/table/table.h"
+#include "sfntly/table/core/font_header_table.h"
+
+namespace sfntly {
+
+// A Loca table - 'loca'.
+class LocaTable : public Table, public RefCounted<LocaTable> {
+ public:
+  class LocaIterator : public PODIterator<int32_t, LocaTable> {
+   public:
+    explicit LocaIterator(LocaTable* table);
+    virtual ~LocaIterator() {}
+
+    virtual bool HasNext();
+    virtual int32_t Next();
+
+   private:
+    int32_t index_;
+  };
+
+  class Builder : public Table::Builder, public RefCounted<Builder> {
+   public:
+    // Constructor scope altered to public for base class to instantiate.
+    Builder(Header* header, WritableFontData* data);
+    Builder(Header* header, ReadableFontData* data);
+    virtual ~Builder();
+
+    static CALLER_ATTACH Builder* CreateBuilder(Header* header,
+                                                WritableFontData* data);
+
+    // Get the format version that will be used when the loca table is
+    // generated.
+    // @return the loca table format version
+    int32_t format_version() { return format_version_; }
+    void set_format_version(int32_t value) { format_version_ = value; }
+
+    // Gets the List of locas for loca table builder. These may be manipulated
+    // in any way by the caller and the changes will be reflected in the final
+    // loca table produced as long as no subsequent call is made to the
+    // SetLocaList(List) method.
+    // If there is no current data for the loca table builder or the loca list
+    // have not been previously set then this will return an empty List.
+    IntegerList* LocaList();
+
+    // Set the list of locas to be used for building this table. If any existing
+    // list was already retrieved with the LocaList() method then the
+    // connection of that previous list to this builder will be broken.
+    void SetLocaList(IntegerList* list);
+
+    // Return the offset for the given glyph id. Valid glyph ids are from 0 to
+    // one less than the number of glyphs. The zero entry is the special entry
+    // for the notdef glyph. The final entry beyond the last glyph id is used to
+    // calculate the size of the last glyph.
+    // @param glyphId the glyph id to get the offset for; must be less than or
+    //        equal to one more than the number of glyph ids
+    // @return the offset in the glyph table to the specified glyph id
+    int32_t GlyphOffset(int32_t glyph_id);
+
+    // Get the length of the data in the glyph table for the specified glyph id.
+    int32_t GlyphLength(int32_t glyph_id);
+
+    // Set the number of glyphs.
+    // This method sets the number of glyphs that the builder will attempt to
+    // parse location data for from the raw binary data. This method only needs
+    // to be called (and <b>must</b> be) when the raw data for this builder has
+    // been changed. It does not by itself reset the data or clear any set loca
+    // list.
+    void SetNumGlyphs(int32_t num_glyphs);
+
+    // Get the number of glyphs that this builder has support for.
+    int NumGlyphs();
+
+    // Revert the loca table builder to the state contained in the last raw data
+    // set on the builder. That raw data may be that read from a font file when
+    // the font builder was created, that set by a user of the loca table
+    // builder, or null data if this builder was created as a new empty builder.
+    void Revert();
+
+    // Get the number of locations or locas. This will be one more than the
+    // number of glyphs for this table since the last loca position is used to
+    // indicate the size of the final glyph.
+    int32_t NumLocas();
+
+    // Get the value from the loca table for the index specified. These are the
+    // raw values from the table that are used to compute the offset and size of
+    // a glyph in the glyph table. Valid index values run from 0 to the number
+    // of glyphs in the font.
+    int32_t Loca(int32_t index);
+
+    virtual CALLER_ATTACH FontDataTable* SubBuildTable(ReadableFontData* data);
+    virtual void SubDataSet();
+    virtual int32_t SubDataSizeToSerialize();
+    virtual bool SubReadyToSerialize();
+    virtual int32_t SubSerialize(WritableFontData* new_data);
+
+   private:
+    // Initialize the internal state from the data. Done lazily since in many
+    // cases the builder will be just creating a table object with no parsing
+    // required.
+    // @param data the data to initialize from
+    void Initialize(ReadableFontData* data);
+
+    // Checks that the glyph id is within the correct range.
+    // @return glyph_id if correct, -1 otherwise.
+    int32_t CheckGlyphRange(int32_t glyph_id);
+
+    int32_t LastGlyphIndex();
+
+    // Internal method to get the loca list if already generated and if not to
+    // initialize the state of the builder.
+    // @return the loca list
+    IntegerList* GetLocaList();
+
+    void ClearLoca(bool nullify);
+
+    int32_t format_version_;  // Note: IndexToLocFormat
+    int32_t num_glyphs_;
+    IntegerList loca_;
+  };
+
+  virtual ~LocaTable();
+
+  int32_t format_version() { return format_version_; }
+  int32_t num_glyphs() { return num_glyphs_; }
+
+  // Return the offset for the given glyph id. Valid glyph ids are from 0 to the
+  // one less than the number of glyphs. The zero entry is the special entry for
+  // the notdef glyph. The final entry beyond the last glyph id is used to
+  // calculate the size of the last glyph.
+  // @param glyphId the glyph id to get the offset for; must be less than or
+  //        equal to one more than the number of glyph ids
+  // @return the offset in the glyph table to the specified glyph id
+  int32_t GlyphOffset(int32_t glyph_id);
+
+  // Get the length of the data in the glyph table for the specified glyph id.
+  int32_t GlyphLength(int32_t glyph_id);
+
+  // Get the number of locations or locas. This will be one more than the number
+  // of glyphs for this table since the last loca position is used to indicate
+  // the size of the final glyph.
+  int32_t NumLocas();
+
+  // Get the value from the loca table for the index specified. Valid index
+  // values run from 0 to the number of glyphs in the font.
+  int32_t Loca(int32_t index);
+
+ private:
+  LocaTable(Header* header,
+            ReadableFontData* data,
+            int32_t format_version,
+            int32_t num_glyphs);
+
+  int32_t format_version_;  // Note: Java's version, renamed to format_version_
+  int32_t num_glyphs_;
+
+  friend class LocaIterator;
+};
+typedef Ptr<LocaTable> LocaTablePtr;
+typedef Ptr<LocaTable::Builder> LocaTableBuilderPtr;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TABLE_TRUETYPE_LOCA_TABLE_H_
diff --git a/cpp/src/sfntly/tag.cc b/cpp/src/sfntly/tag.cc
new file mode 100644
index 0000000..c9d8c29
--- /dev/null
+++ b/cpp/src/sfntly/tag.cc
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/tag.h"
+#include "sfntly/port/endian.h"
+
+// Use a macro instead of GenerateTag() because gcc 4.4.3 creates static
+// initializers in that case.
+#define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d);
+
+namespace sfntly {
+
+const int32_t Tag::ttcf = TAG('t', 't', 'c', 'f');
+const int32_t Tag::cmap = TAG('c', 'm', 'a', 'p');
+const int32_t Tag::head = TAG('h', 'e', 'a', 'd');
+const int32_t Tag::hhea = TAG('h', 'h', 'e', 'a');
+const int32_t Tag::hmtx = TAG('h', 'm', 't', 'x');
+const int32_t Tag::maxp = TAG('m', 'a', 'x', 'p');
+const int32_t Tag::name = TAG('n', 'a', 'm', 'e');
+const int32_t Tag::OS_2 = TAG('O', 'S', '/', '2');
+const int32_t Tag::post = TAG('p', 'o', 's', 't');
+const int32_t Tag::cvt  = TAG('c', 'v', 't', ' ');
+const int32_t Tag::fpgm = TAG('f', 'p', 'g', 'm');
+const int32_t Tag::glyf = TAG('g', 'l', 'y', 'f');
+const int32_t Tag::loca = TAG('l', 'o', 'c', 'a');
+const int32_t Tag::prep = TAG('p', 'r', 'e', 'p');
+const int32_t Tag::CFF  = TAG('C', 'F', 'F', ' ');
+const int32_t Tag::VORG = TAG('V', 'O', 'R', 'G');
+const int32_t Tag::EBDT = TAG('E', 'B', 'D', 'T');
+const int32_t Tag::EBLC = TAG('E', 'B', 'L', 'C');
+const int32_t Tag::EBSC = TAG('E', 'B', 'S', 'C');
+const int32_t Tag::BASE = TAG('B', 'A', 'S', 'E');
+const int32_t Tag::GDEF = TAG('G', 'D', 'E', 'F');
+const int32_t Tag::GPOS = TAG('G', 'P', 'O', 'S');
+const int32_t Tag::GSUB = TAG('G', 'S', 'U', 'B');
+const int32_t Tag::JSTF = TAG('J', 'S', 'T', 'F');
+const int32_t Tag::DSIG = TAG('D', 'S', 'I', 'G');
+const int32_t Tag::gasp = TAG('g', 'a', 's', 'p');
+const int32_t Tag::hdmx = TAG('h', 'd', 'm', 'x');
+const int32_t Tag::kern = TAG('k', 'e', 'r', 'n');
+const int32_t Tag::LTSH = TAG('L', 'T', 'S', 'H');
+const int32_t Tag::PCLT = TAG('P', 'C', 'L', 'T');
+const int32_t Tag::VDMX = TAG('V', 'D', 'M', 'X');
+const int32_t Tag::vhea = TAG('v', 'h', 'e', 'a');
+const int32_t Tag::vmtx = TAG('v', 'm', 't', 'x');
+const int32_t Tag::bsln = TAG('b', 's', 'l', 'n');
+const int32_t Tag::feat = TAG('f', 'e', 'a', 't');
+const int32_t Tag::lcar = TAG('l', 'c', 'a', 'r');
+const int32_t Tag::morx = TAG('m', 'o', 'r', 'x');
+const int32_t Tag::opbd = TAG('o', 'p', 'b', 'd');
+const int32_t Tag::prop = TAG('p', 'r', 'o', 'p');
+const int32_t Tag::Feat = TAG('F', 'e', 'a', 't');
+const int32_t Tag::Glat = TAG('G', 'l', 'a', 't');
+const int32_t Tag::Gloc = TAG('G', 'l', 'o', 'c');
+const int32_t Tag::Sile = TAG('S', 'i', 'l', 'e');
+const int32_t Tag::Silf = TAG('S', 'i', 'l', 'f');
+const int32_t Tag::bhed = TAG('b', 'h', 'e', 'd');
+const int32_t Tag::bdat = TAG('b', 'd', 'a', 't');
+const int32_t Tag::bloc = TAG('b', 'l', 'o', 'c');
+
+const int32_t CFF_TABLE_ORDERING[] = {
+    Tag::head,
+    Tag::hhea,
+    Tag::maxp,
+    Tag::OS_2,
+    Tag::name,
+    Tag::cmap,
+    Tag::post,
+    Tag::CFF };
+const size_t CFF_TABLE_ORDERING_SIZE =
+    sizeof(CFF_TABLE_ORDERING) / sizeof(int32_t);
+
+const int32_t TRUE_TYPE_TABLE_ORDERING[] = {
+    Tag::head,
+    Tag::hhea,
+    Tag::maxp,
+    Tag::OS_2,
+    Tag::hmtx,
+    Tag::LTSH,
+    Tag::VDMX,
+    Tag::hdmx,
+    Tag::cmap,
+    Tag::fpgm,
+    Tag::prep,
+    Tag::cvt,
+    Tag::loca,
+    Tag::glyf,
+    Tag::kern,
+    Tag::name,
+    Tag::post,
+    Tag::gasp,
+    Tag::PCLT,
+    Tag::DSIG };
+const size_t TRUE_TYPE_TABLE_ORDERING_SIZE =
+    sizeof(TRUE_TYPE_TABLE_ORDERING) / sizeof(int32_t);
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/tag.h b/cpp/src/sfntly/tag.h
new file mode 100644
index 0000000..0ecbab8
--- /dev/null
+++ b/cpp/src/sfntly/tag.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TAG_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TAG_H_
+
+#include <cstddef>
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+// Font identification tags used for tables, features, etc.
+// Tag names are consistent with the OpenType and sfnt specs.
+struct Tag {
+  static const int32_t ttcf;
+
+  // Table Type Tags
+  // required tables
+  static const int32_t cmap;
+  static const int32_t head;
+  static const int32_t hhea;
+  static const int32_t hmtx;
+  static const int32_t maxp;
+  static const int32_t name;
+  static const int32_t OS_2;
+  static const int32_t post;
+
+  // TrueType outline tables
+  static const int32_t cvt;
+  static const int32_t fpgm;
+  static const int32_t glyf;
+  static const int32_t loca;
+  static const int32_t prep;
+
+  // PostScript outline tables
+  static const int32_t CFF;
+  static const int32_t VORG;
+
+  // opentype bitmap glyph outlines
+  static const int32_t EBDT;
+  static const int32_t EBLC;
+  static const int32_t EBSC;
+
+  // advanced typographic features
+  static const int32_t BASE;
+  static const int32_t GDEF;
+  static const int32_t GPOS;
+  static const int32_t GSUB;
+  static const int32_t JSTF;
+
+  // other
+  static const int32_t DSIG;
+  static const int32_t gasp;
+  static const int32_t hdmx;
+  static const int32_t kern;
+  static const int32_t LTSH;
+  static const int32_t PCLT;
+  static const int32_t VDMX;
+  static const int32_t vhea;
+  static const int32_t vmtx;
+
+  // AAT tables
+  static const int32_t bsln;
+  static const int32_t feat;
+  static const int32_t lcar;
+  static const int32_t morx;
+  static const int32_t opbd;
+  static const int32_t prop;
+
+  // Graphite tables
+  static const int32_t Feat;
+  static const int32_t Glat;
+  static const int32_t Gloc;
+  static const int32_t Sile;
+  static const int32_t Silf;
+
+  // truetype bitmap font tables
+  static const int32_t bhed;
+  static const int32_t bdat;
+  static const int32_t bloc;
+};
+
+// Create integer tag value for human readable tag name.
+inline int32_t GenerateTag(int32_t a, int32_t b, int32_t c, int32_t d) {
+  return (a << 24) | (b << 16) | (c << 8) | d;
+}
+
+// Translate tag to human readable string.
+// The Caller must delete[] the returned value.
+inline char* TagToString(int32_t tag) {
+  char *name = new char[5];
+  name[0] = static_cast<char>((tag & 0xff000000) >> 24);
+  name[1] = static_cast<char>((tag & 0x00ff0000) >> 16);
+  name[2] = static_cast<char>((tag & 0x0000ff00) >> 8);
+  name[3] = static_cast<char>(tag & 0x000000ff);
+  name[4] = 0;
+  return name;
+}
+
+// Note: For Java, these two orderings are in Font class.  Moved here to avoid
+//       VC++ bug of not populating correct values.
+extern const int32_t CFF_TABLE_ORDERING[];
+extern const size_t CFF_TABLE_ORDERING_SIZE;
+extern const int32_t TRUE_TYPE_TABLE_ORDERING[];
+extern const size_t TRUE_TYPE_TABLE_ORDERING_SIZE;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TAG_H_
diff --git a/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.cc b/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.cc
new file mode 100644
index 0000000..b3d6b07
--- /dev/null
+++ b/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/tools/subsetter/glyph_table_subsetter.h"
+
+#include "sfntly/table/truetype/glyph_table.h"
+#include "sfntly/table/truetype/loca_table.h"
+#include "sfntly/tag.h"
+#include "sfntly/tools/subsetter/subsetter.h"
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+
+const int32_t kGlyphTableSubsetterTags[2] = {Tag::glyf, Tag::loca};
+
+GlyphTableSubsetter::GlyphTableSubsetter()
+    : TableSubsetterImpl(kGlyphTableSubsetterTags, 2) {
+}
+
+GlyphTableSubsetter::~GlyphTableSubsetter() {}
+
+bool GlyphTableSubsetter::Subset(Subsetter* subsetter,
+                                 Font* font,
+                                 Font::Builder* font_builder) {
+  assert(font);
+  assert(subsetter);
+  assert(font_builder);
+
+  IntegerList* permutation_table = subsetter->GlyphPermutationTable();
+  if (!permutation_table || permutation_table->empty())
+    return false;
+
+  GlyphTablePtr glyph_table = down_cast<GlyphTable*>(font->GetTable(Tag::glyf));
+  LocaTablePtr loca_table = down_cast<LocaTable*>(font->GetTable(Tag::loca));
+  if (glyph_table == NULL || loca_table == NULL) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw RuntimeException("Font to subset is not valid.");
+#endif
+    return false;
+  }
+
+  GlyphTableBuilderPtr glyph_table_builder =
+      down_cast<GlyphTable::Builder*>
+      (font_builder->NewTableBuilder(Tag::glyf));
+  LocaTableBuilderPtr loca_table_builder =
+      down_cast<LocaTable::Builder*>
+      (font_builder->NewTableBuilder(Tag::loca));
+  if (glyph_table_builder == NULL || loca_table_builder == NULL) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+    throw RuntimeException("Builder for subset is not valid.");
+#endif
+    return false;
+  }
+  GlyphTable::GlyphBuilderList* glyph_builders =
+      glyph_table_builder->GlyphBuilders();
+  for (IntegerList::iterator old_glyph_id = permutation_table->begin(),
+                             old_glyph_id_end = permutation_table->end();
+                             old_glyph_id != old_glyph_id_end; ++old_glyph_id) {
+    int old_offset = loca_table->GlyphOffset(*old_glyph_id);
+    int old_length = loca_table->GlyphLength(*old_glyph_id);
+    GlyphPtr glyph;
+    glyph.Attach(glyph_table->GetGlyph(old_offset, old_length));
+    ReadableFontDataPtr data = glyph->ReadFontData();
+    WritableFontDataPtr copy_data;
+    copy_data.Attach(WritableFontData::CreateWritableFontData(data->Length()));
+    data->CopyTo(copy_data);
+    GlyphBuilderPtr glyph_builder;
+    glyph_builder.Attach(glyph_table_builder->GlyphBuilder(copy_data));
+    glyph_builders->push_back(glyph_builder);
+  }
+  IntegerList loca_list;
+  glyph_table_builder->GenerateLocaList(&loca_list);
+  loca_table_builder->SetLocaList(&loca_list);
+  return true;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.h b/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.h
new file mode 100644
index 0000000..88c7044
--- /dev/null
+++ b/cpp/src/sfntly/tools/subsetter/glyph_table_subsetter.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_
+
+#include "sfntly/tools/subsetter/table_subsetter_impl.h"
+
+namespace sfntly {
+
+class GlyphTableSubsetter : public TableSubsetterImpl,
+                            public RefCounted<GlyphTableSubsetter> {
+ public:
+  GlyphTableSubsetter();
+  virtual ~GlyphTableSubsetter();
+
+  virtual bool Subset(Subsetter* subsetter,
+                      Font* font,
+                      Font::Builder* font_builder);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_GLYPH_TABLE_SUBSETTER_H_
diff --git a/cpp/src/sfntly/tools/subsetter/subsetter.cc b/cpp/src/sfntly/tools/subsetter/subsetter.cc
new file mode 100644
index 0000000..7d98779
--- /dev/null
+++ b/cpp/src/sfntly/tools/subsetter/subsetter.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/tools/subsetter/subsetter.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "sfntly/tools/subsetter/glyph_table_subsetter.h"
+
+namespace sfntly {
+
+Subsetter::Subsetter(Font* font, FontFactory* font_factory) {
+  font_ = font;
+  font_factory_ = font_factory;
+  TableSubsetterPtr subsetter = new GlyphTableSubsetter();
+  // TODO(arthurhsu): IMPLEMENT: CMap table subsetter
+  table_subsetters_.push_back(subsetter);
+}
+
+Subsetter::~Subsetter() {
+  font_factory_.Release();
+  font_.Release();
+  table_subsetters_.clear();
+}
+
+void Subsetter::SetGlyphs(IntegerList* glyphs) {
+  new_to_old_glyphs_ = *glyphs;
+}
+
+void Subsetter::SetCMaps(CMapIdList* cmap_ids, int32_t number) {
+  UNREFERENCED_PARAMETER(cmap_ids);
+  UNREFERENCED_PARAMETER(number);
+  // TODO(arthurhsu): IMPLEMENT
+}
+
+void Subsetter::SetRemoveTables(IntegerSet* remove_tables) {
+  remove_tables_ = *remove_tables;
+}
+
+CALLER_ATTACH Font::Builder* Subsetter::Subset() {
+  FontBuilderPtr font_builder;
+  font_builder.Attach(font_factory_->NewFontBuilder());
+
+  IntegerSet table_tags;
+  for (TableMap::const_iterator i = font_->GetTableMap()->begin(),
+                                e = font_->GetTableMap()->end(); i != e; ++i) {
+    table_tags.insert(i->first);
+  }
+  if (!remove_tables_.empty()) {
+    IntegerSet result;
+    std::set_difference(table_tags.begin(), table_tags.end(),
+                        remove_tables_.begin(), remove_tables_.end(),
+                        std::inserter(result, result.end()));
+    table_tags = result;
+  }
+  for (TableSubsetterList::iterator
+           table_subsetter = table_subsetters_.begin(),
+           table_subsetter_end = table_subsetters_.end();
+           table_subsetter != table_subsetter_end; ++table_subsetter) {
+    bool handled = (*table_subsetter)->Subset(this, font_, font_builder);
+    if (handled) {
+      IntegerSet* handled_tags = (*table_subsetter)->TagsHandled();
+      IntegerSet result;
+      std::set_difference(table_tags.begin(), table_tags.end(),
+                          handled_tags->begin(), handled_tags->end(),
+                          std::inserter(result, result.end()));
+      table_tags = result;
+    }
+  }
+  for (IntegerSet::iterator tag = table_tags.begin(),
+                            tag_end = table_tags.end(); tag != tag_end; ++tag) {
+    Table* table = font_->GetTable(*tag);
+    if (table) {
+      font_builder->NewTableBuilder(*tag, table->ReadFontData());
+    }
+  }
+  return font_builder.Detach();
+}
+
+IntegerList* Subsetter::GlyphPermutationTable() {
+  return &new_to_old_glyphs_;
+}
+
+CMapIdList* Subsetter::CMapId() {
+  return &cmap_ids_;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/tools/subsetter/subsetter.h b/cpp/src/sfntly/tools/subsetter/subsetter.h
new file mode 100644
index 0000000..85940a7
--- /dev/null
+++ b/cpp/src/sfntly/tools/subsetter/subsetter.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_
+
+#include <vector>
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/tools/subsetter/table_subsetter.h"
+
+namespace sfntly {
+
+class Subsetter : public RefCounted<Subsetter> {
+ public:
+  Subsetter(Font* font, FontFactory* font_factory);
+  virtual ~Subsetter();
+
+  virtual void SetGlyphs(IntegerList* glyphs);
+
+  // Set the cmaps to be used in the subsetted font. The cmaps are listed in
+  // order of priority and the number parameter gives a count of how many of the
+  // list should be put into the subsetted font. If there are no matches in the
+  // font for any of the provided cmap ids which would lead to a font with no
+  // cmap then an error will be thrown during subsetting.
+  // The two most common cases would be: <list>
+  // * a list of one or more cmap ids with a count setting of 1
+  //     This will use the list of cmap ids as an ordered priority and look for
+  //     an available cmap in the font that matches the requests. Only the first
+  //     such match will be placed in the subsetted font.
+  // * a list of one or more cmap ids with a count setting equal to the list
+  //   length
+  //     This will use the list of cmap ids and try to place each one specified
+  //     into the subsetted font.
+  // @param cmapIds the cmap ids to use for the subsetted font
+  // @param number the maximum number of cmaps to place in the subsetted font
+  virtual void SetCMaps(CMapIdList* cmap_ids, int32_t number);
+
+  virtual void SetRemoveTables(IntegerSet* remove_tables);
+  virtual CALLER_ATTACH Font::Builder* Subset();
+  virtual IntegerList* GlyphPermutationTable();
+  virtual CMapIdList* CMapId();
+
+ private:
+  FontPtr font_;
+  FontFactoryPtr font_factory_;
+  TableSubsetterList table_subsetters_;
+
+  // Settings from user
+  IntegerSet remove_tables_;
+  IntegerList new_to_old_glyphs_;
+  CMapIdList cmap_ids_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_SUBSETTER_H_
diff --git a/cpp/src/sfntly/tools/subsetter/table_subsetter.h b/cpp/src/sfntly/tools/subsetter/table_subsetter.h
new file mode 100644
index 0000000..1336615
--- /dev/null
+++ b/cpp/src/sfntly/tools/subsetter/table_subsetter.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_
+
+#include <vector>
+
+#include "sfntly/font.h"
+
+namespace sfntly {
+
+class Subsetter;
+class TableSubsetter : virtual public RefCount {
+ public:
+  virtual IntegerSet* TagsHandled() = 0;
+  virtual bool TagHandled(int32_t tag) = 0;
+  virtual bool Subset(Subsetter* subsetter, Font* font,
+                      Font::Builder* font_builder) = 0;
+};
+typedef Ptr<TableSubsetter> TableSubsetterPtr;
+typedef std::vector<TableSubsetterPtr> TableSubsetterList;
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_H_
diff --git a/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.cc b/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.cc
new file mode 100644
index 0000000..f239c78
--- /dev/null
+++ b/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/tools/subsetter/table_subsetter_impl.h"
+
+namespace sfntly {
+
+TableSubsetterImpl::TableSubsetterImpl(const int32_t* tags,
+                                       size_t tags_length) {
+  for (size_t i = 0; i < tags_length; ++i) {
+    tags_.insert(tags[i]);
+  }
+}
+
+TableSubsetterImpl::~TableSubsetterImpl() {}
+
+bool TableSubsetterImpl::TagHandled(int32_t tag) {
+  return tags_.find(tag) != tags_.end();
+}
+
+IntegerSet* TableSubsetterImpl::TagsHandled() {
+  return &tags_;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.h b/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.h
new file mode 100644
index 0000000..de0d9a9
--- /dev/null
+++ b/cpp/src/sfntly/tools/subsetter/table_subsetter_impl.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_
+#define SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_
+
+#include "sfntly/tools/subsetter/table_subsetter.h"
+
+namespace sfntly {
+
+class TableSubsetterImpl : public TableSubsetter {
+ public:
+  TableSubsetterImpl(const int32_t* tags, size_t tags_length);
+  virtual ~TableSubsetterImpl();
+  virtual bool TagHandled(int32_t tag);
+  virtual IntegerSet* TagsHandled();
+
+ protected:
+  IntegerSet tags_;
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_SFNTLY_TOOLS_SUBSETTER_TABLE_SUBSETTER_IMPL_H_
diff --git a/cpp/src/test/autogenerated/cmap_basic_test.cc b/cpp/src/test/autogenerated/cmap_basic_test.cc
new file mode 100644
index 0000000..aae35e1
--- /dev/null
+++ b/cpp/src/test/autogenerated/cmap_basic_test.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// type.h needs to be included first because of building issues on Windows
+// Type aliases we delcare are defined in other headers and make the build
+// fail otherwise.
+#include "sfntly/port/type.h"
+#include <assert.h>
+#include <stdio.h>
+#include <unicode/ucnv.h>
+
+#include <iostream>
+#include <string>
+
+#include "gtest/gtest.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/table/core/font_header_table.h"
+#include "sfntly/tag.h"
+#include "test/autogenerated/cmap_test_data.h"
+#include "test/test_font_utils.h"
+#include "test/test_utils.h"
+#include "test/test_xml_utils.h"
+
+namespace sfntly {
+
+#if GTEST_HAS_PARAM_TEST
+
+using ::testing::TestWithParam;
+using ::testing::Values;
+
+class CMapBasicTests : public :: testing::TestWithParam<const char*> {
+ public:
+  CMapBasicTests() {}
+  virtual void SetUp();
+  virtual void TearDown() {}
+
+  Ptr<CMapTable> cmap_table_;
+  TiXmlDocument document_;
+};
+
+void CMapBasicTests::SetUp() {
+  // Loading the font
+  Ptr<FontFactory> font_factory;
+  font_factory.Attach(FontFactory::GetInstance());
+  FontArray font_array;
+  std::string font_name = "../../";
+#if defined (WIN32)
+  font_name += "../";
+#endif
+  font_name += std::string(GetParam());
+  LoadFont(font_name.c_str(), font_factory, &font_array);
+  ASSERT_FALSE(font_array.empty());
+  Ptr<Font> font = font_array.at(0);
+  ASSERT_NE(font, reinterpret_cast<Font*>(NULL));
+  cmap_table_ = down_cast<CMapTable*>(font->GetTable(Tag::cmap));
+  if (!cmap_table_)
+    fprintf(stderr, "No CMap: %s\n", font_name.c_str());
+  ASSERT_NE(cmap_table_, reinterpret_cast<CMapTable*>(NULL));
+
+  // Loading the XML file
+  document_ = TiXmlDocument((font_name + ".xml").c_str());
+  ASSERT_TRUE(document_.LoadFile());
+}
+
+TEST_P(CMapBasicTests, BasicTest) {
+  TiXmlNodeVector* cmap_table = GetNodesWithName(&document_, "cmap_table");
+  // A font can only have one CMap table
+  ASSERT_EQ(cmap_table->size(), (size_t)1);
+  TiXmlNodeVector* cmaps = GetNodesWithName(cmap_table->at(0), "cmap");
+  const TiXmlAttribute* num_cmaps_attr = GetAttribute(cmap_table->at(0),
+                                                      "num_cmaps");
+  ASSERT_NE(num_cmaps_attr, reinterpret_cast<TiXmlAttribute*>(NULL));
+  // But there may be more than one CMap in this table
+  ASSERT_LE(cmaps->size(), (size_t)num_cmaps_attr->IntValue());
+  for (TiXmlNodeVector::iterator it = cmaps->begin();
+       it != cmaps->end(); ++it) {
+    int32_t platform_id = GetAttribute(*it, "platform_id")->IntValue();
+    int32_t encoding_id = GetAttribute(*it, "encoding_id")->IntValue();
+    Ptr<CMapTable::CMap> cmap;
+    cmap.Attach(cmap_table_->GetCMap(platform_id, encoding_id));
+    if (!cmap) {
+      fprintf(stderr, "Cannot test unsupported CMapFormat%d\n",
+              GetAttribute(*it, "format")->IntValue());
+      continue;
+    }
+    ASSERT_EQ(cmap->platform_id(), platform_id);
+    ASSERT_EQ(cmap->encoding_id(), encoding_id);
+    TiXmlNodeVector* maps = GetNodesWithName(*it, "map");
+    for (TiXmlNodeVector::iterator jt = maps->begin();
+         jt != maps->end(); ++jt) {
+      int32_t character;
+#if defined (WIN32)
+      sscanf_s(GetAttribute(*jt, "char")->Value(), "%x", &character);
+#else
+      sscanf(GetAttribute(*jt, "char")->Value(), "%x", &character);
+#endif
+      int32_t glyph_id = GetAttribute(*jt, "gid")->IntValue();
+      ASSERT_EQ(cmap->GlyphId(character), glyph_id);
+    }
+    delete maps;
+  }
+  delete cmaps;
+  delete cmap_table;
+}
+
+INSTANTIATE_TEST_CASE_P(CMapBasicTests,
+                        CMapBasicTests,
+                        ::testing::ValuesIn(cmap_test_data::kAllTests));
+
+#else
+
+TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
+
+#endif  // GTEST_HAS_PARAM
+}
diff --git a/cpp/src/test/autogenerated/cmap_test_data.h b/cpp/src/test/autogenerated/cmap_test_data.h
new file mode 100644
index 0000000..4a9f267
--- /dev/null
+++ b/cpp/src/test/autogenerated/cmap_test_data.h
@@ -0,0 +1,185 @@
+/*
+ * !!! DO NOT EDIT !!!
+ * THIS FILE IS GENERATED BY A SCRIPT.
+ * FOR MORE DETAILS SEE 'README-test_data.txt'.
+ */
+
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TYPOGRAPHY_FONT_SFNTLY_SRC_TEST_AUTOGENERATED_CMAP_TEST_DATA_H_
+#define TYPOGRAPHY_FONT_SFNTLY_SRC_TEST_AUTOGENERATED_CMAP_TEST_DATA_H_
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+namespace cmap_test_data {
+const char* kAllTests[] = {
+  "data/fonts/cousine/Cousine-BoldItalic.ttf",
+  "data/fonts/cousine/Cousine-Bold.ttf",
+  "data/fonts/cousine/Cousine-Regular.ttf",
+  "data/fonts/cousine/Cousine-Italic.ttf",
+  "data/fonts/cedarvillecursive/Cedarville-Cursive.ttf",
+  "data/fonts/dancingscript/DancingScript-Bold.ttf",
+  "data/fonts/dancingscript/DancingScript-Regular.ttf",
+  "data/fonts/damion/Damion-Regular.ttf",
+  "data/fonts/annieuseyourtelescope/AnnieUseYourTelescope.ttf",
+  "data/fonts/deliusswashcaps/DeliusSwashCaps-Regular.ttf",
+  "data/fonts/delius/Delius-Regular.ttf",
+  "data/fonts/coveredbyyourgrace/CoveredByYourGrace.ttf",
+  "data/fonts/ebgaramond/EBGaramond-Regular.ttf",
+  "data/fonts/cabinsketch/CabinSketch-Bold.ttf",
+  "data/fonts/allan/Allan-Bold.ttf",
+  "data/fonts/coda/Coda-Caption-Heavy.ttf",
+  "data/fonts/coda/Coda-Heavy.ttf",
+  "data/fonts/forum/Forum-Regular.ttf",
+  "data/fonts/alike/Alike-Regular.ttf",
+  "data/fonts/corben/Corben-Bold.ttf",
+  "data/fonts/caudex/Caudex-Regular.ttf",
+  "data/fonts/caudex/Caudex-BoldItalic.ttf",
+  "data/fonts/caudex/Caudex-Italic.ttf",
+  "data/fonts/caudex/Caudex-Bold.ttf",
+  "data/fonts/cabin/Cabin-MediumItalic.ttf",
+  "data/fonts/cabin/Cabin-SemiBold.ttf",
+  "data/fonts/cabin/Cabin-SemiBoldItalic.ttf",
+  "data/fonts/cabin/Cabin-BoldItalic.ttf",
+  "data/fonts/cabin/Cabin-Medium.ttf",
+  "data/fonts/cabin/Cabin-Italic.ttf",
+  "data/fonts/cabin/Cabin-Bold.ttf",
+  "data/fonts/cabin/Cabin-Regular.ttf",
+  "data/fonts/dawningofanewday/DawningofaNewDay.ttf",
+  "data/fonts/dangrek/Dangrek.ttf",
+  "data/fonts/blackopsone/BlackOpsOne.ttf",
+  "data/fonts/francoisone/FrancoisOne.ttf",
+  "data/fonts/bowlbyone/BowlbyOne.ttf",
+  "data/fonts/bowlbyone/BowlbyOneSC.ttf",
+  "data/fonts/calligraffiti/Calligraffiti.ttf",
+  "data/fonts/bangers/Bangers.ttf",
+  "data/fonts/astloch/Astloch-Regular.ttf",
+  "data/fonts/astloch/Astloch-Bold.ttf",
+  "data/fonts/angkor/Angkor.ttf",
+  "data/fonts/abrilfatface/AbrilFatface-Regular.ttf",
+  "data/fonts/cantarell/Cantarell-BoldOblique.ttf",
+  "data/fonts/cantarell/Cantarell-Oblique.ttf",
+  "data/fonts/cantarell/Cantarell-Bold.ttf",
+  "data/fonts/cantarell/Cantarell-Regular.ttf",
+  "data/fonts/arvo/Arvo-Bold.ttf",
+  "data/fonts/arvo/Arvo-Italic.ttf",
+  "data/fonts/arvo/Arvo-BoldItalic.ttf",
+  "data/fonts/arvo/Arvo-Regular.ttf",
+  "data/fonts/chewy/Chewy.ttf",
+  "data/fonts/bigshotone/BigshotOne.ttf",
+  "data/fonts/chenla/Chenla.ttf",
+  "data/fonts/bayon/Bayon.ttf",
+  "data/fonts/coustard/Coustard-Black.ttf",
+  "data/fonts/coustard/Coustard-Regular.ttf",
+  "data/fonts/amaticsc/AmaticSC-Bold.ttf",
+  "data/fonts/amaticsc/AmaticSC-Regular.ttf",
+  "data/fonts/comfortaa/Comfortaa-Light.ttf",
+  "data/fonts/comfortaa/Comfortaa-Bold.ttf",
+  "data/fonts/comfortaa/Comfortaa-Regular.ttf",
+  "data/fonts/expletussans/ExpletusSans-Bold.ttf",
+  "data/fonts/expletussans/ExpletusSans-MediumItalic.ttf",
+  "data/fonts/expletussans/ExpletusSans-Medium.ttf",
+  "data/fonts/expletussans/ExpletusSans-SemiBold.ttf",
+  "data/fonts/expletussans/ExpletusSans-Regular.ttf",
+  "data/fonts/expletussans/ExpletusSans-Italic.ttf",
+  "data/fonts/expletussans/ExpletusSans-SemiBoldItalic.ttf",
+  "data/fonts/expletussans/ExpletusSans-BoldItalic.ttf",
+  "data/fonts/aubrey/Aubrey-Regular.ttf",
+  "data/fonts/antic/Antic-Regular.ttf",
+  "data/fonts/copse/Copse-Regular.ttf",
+  "data/fonts/daysone/DaysOne-Regular.ttf",
+  "data/fonts/actor/Actor-Regular.ttf",
+  "data/fonts/bentham/Bentham-Regular.ttf",
+  "data/fonts/federo/Federo-Regular.ttf",
+  "data/fonts/arimo/Arimo-Italic.ttf",
+  "data/fonts/arimo/Arimo-BoldItalic.ttf",
+  "data/fonts/arimo/Arimo-Bold.ttf",
+  "data/fonts/arimo/Arimo-Regular.ttf",
+  "data/fonts/felltypes/IMFeDPsc28P.ttf",
+  "data/fonts/felltypes/IMFeGPrm28P.ttf",
+  "data/fonts/felltypes/IMFeENsc28P.ttf",
+  "data/fonts/felltypes/IMFePIit28P.ttf",
+  "data/fonts/felltypes/IMFeDPrm28P.ttf",
+  "data/fonts/felltypes/IMFePIrm28P.ttf",
+  "data/fonts/felltypes/IMFeFCrm28P.ttf",
+  "data/fonts/felltypes/IMFeGPit28P.ttf",
+  "data/fonts/felltypes/IMFeENit28P.ttf",
+  "data/fonts/felltypes/IMFeDPit28P.ttf",
+  "data/fonts/felltypes/IMFeENrm28P.ttf",
+  "data/fonts/felltypes/IMFeGPsc28P.ttf",
+  "data/fonts/felltypes/IMFePIsc28P.ttf",
+  "data/fonts/felltypes/IMFeFCsc28P.ttf",
+  "data/fonts/felltypes/IMFeFCit28P.ttf",
+  "data/fonts/bokor/Bokor.ttf",
+  "data/fonts/didactgothic/DidactGothic.ttf",
+  "data/fonts/allerta/Allerta-Medium.ttf",
+  "data/fonts/allerta/Allerta-Stencil.ttf",
+  "data/fonts/buda/Buda-Light.ttf",
+  "data/fonts/brawler/Brawler-Regular.ttf",
+  "data/fonts/carterone/CarterOne.ttf",
+  "data/fonts/candal/Candal.ttf",
+  "data/fonts/dorsa/Dorsa-Regular.ttf",
+  "data/fonts/crimson/CrimsonText-BoldItalic.ttf",
+  "data/fonts/crimson/CrimsonText-Bold.ttf",
+  "data/fonts/crimson/CrimsonText-Italic.ttf",
+  "data/fonts/crimson/CrimsonText-Roman.ttf",
+  "data/fonts/crimson/CrimsonText-Semibold.ttf",
+  "data/fonts/crimson/CrimsonText-SemiboldItalic.ttf",
+  "data/fonts/amaranth/Amaranth-Italic.ttf",
+  "data/fonts/amaranth/Amaranth-Bold.ttf",
+  "data/fonts/amaranth/Amaranth-Regular.ttf",
+  "data/fonts/amaranth/Amaranth-BoldItalic.ttf",
+  "data/fonts/crushed/Crushed.ttf",
+  "data/fonts/adamina/Adamina-Regular.ttf",
+  "data/fonts/aldrich/Aldrich-Regular.ttf",
+  "data/fonts/fanwoodtext/FanwoodText-Italic.ttf",
+  "data/fonts/fanwoodtext/FanwoodText-Regular.ttf",
+  "data/fonts/anonymouspro/AnonymousPro-Regular.ttf",
+  "data/fonts/anonymouspro/AnonymousPro-Bold.ttf",
+  "data/fonts/anonymouspro/AnonymousPro-Italic.ttf",
+  "data/fonts/anonymouspro/AnonymousPro-BoldItalic.ttf",
+  "data/fonts/bevan/Bevan.ttf",
+  "data/fonts/artifika/Artifika-Regular.ttf",
+  "data/fonts/anton/Anton.ttf",
+  "data/fonts/battambang/Battambang-Regular.ttf",
+  "data/fonts/battambang/Battambang-Bold.ttf",
+  "data/fonts/carme/Carme-Regular.ttf",
+  "data/fonts/cherrycreamsoda/CherryCreamSoda.ttf",
+  "data/fonts/deliusunicase/DeliusUnicase-Regular.ttf",
+  "data/fonts/comingsoon/ComingSoon.ttf",
+  "data/fonts/freehand/Freehand.ttf",
+  "data/fonts/alice/Alice-Regular.ttf",
+  "data/fonts/contrail/Contrail-Regular.ttf",
+  "data/fonts/cardo/Cardo-Bold.ttf",
+  "data/fonts/cardo/Cardo-Italic.ttf",
+  "data/fonts/cardo/Cardo-Regular.ttf",
+  "data/fonts/asset/Asset.ttf",
+  "data/fonts/changaone/ChangaOne-Regular.ttf",
+  "data/fonts/aclonica/Aclonica.ttf",
+  "data/fonts/craftygirls/CraftyGirls.ttf",
+  "data/fonts/architectsdaughter/ArchitectsDaughter.ttf",
+  "data/fonts/content/Content-Bold.ttf",
+  "data/fonts/content/Content-Regular.ttf",
+  "data/fonts/abel/Abel-Regular.ttf",
+  "data/fonts/cuprum/Cuprum.ttf",
+  "data/fonts/andika/Andika-R.ttf"
+};
+}  // namespace cmap_test_data
+}  // namespace sfntly
+
+#endif  // TYPOGRAPHY_FONT_SFNTLY_SRC_TEST_AUTOGENERATED_CMAP_TEST_DATA_H_
diff --git a/cpp/src/test/bitmap_table_test.cc b/cpp/src/test/bitmap_table_test.cc
new file mode 100644
index 0000000..df3ffc0
--- /dev/null
+++ b/cpp/src/test/bitmap_table_test.cc
@@ -0,0 +1,209 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/port/file_input_stream.h"
+#include "sfntly/port/memory_input_stream.h"
+#include "sfntly/port/memory_output_stream.h"
+#include "sfntly/table/bitmap/ebdt_table.h"
+#include "sfntly/table/bitmap/eblc_table.h"
+#include "sfntly/table/bitmap/index_sub_table_format3.h"
+#include "sfntly/table/bitmap/index_sub_table_format4.h"
+#include "test/test_data.h"
+#include "test/test_font_utils.h"
+
+namespace sfntly {
+
+const int32_t NUM_STRIKES = 4;
+const int32_t STRIKE1_ARRAY_OFFSET = 0xc8;
+const int32_t STRIKE1_INDEX_TABLE_SIZE = 0x4f4;
+const int32_t STRIKE1_NUM_INDEX_TABLES = 1;
+const int32_t STRIKE1_COLOR_REF = 0;
+const int32_t STRIKE1_START_GLYPH_INDEX = 0;
+const int32_t STRIKE1_END_GLYPH_INDEX = 623;
+const int32_t STRIKE1_PPEM_X = 10;
+const int32_t STRIKE1_PPEM_Y = 10;
+const int32_t STRIKE1_BIT_DEPTH = 1;
+const int32_t STRIKE1_FLAGS = 0x01;
+
+const int32_t STRIKE4_SUB1_INDEX_FORMAT = 3;
+const int32_t STRIKE4_SUB1_IMAGE_FORMAT = 1;
+const int32_t STRIKE4_SUB1_IMAGE_DATA_OFFSET = 0x00005893;
+const int32_t STRIKE4_SUB1_GLYPH_OFFSET[] = {
+    0x00005893, 0x00005898, 0x0000589d, 0x000058a2, 0x000058a7,
+    0x000058b2, 0x000058c2, 0x000058d0, 0x000058de, 0x000058e6 };
+const int32_t NUM_STRIKE4_SUB1_GLYPH_OFFSET = 10;
+const int32_t STRIKE4_SUB1_GLYPH2_LENGTH = 0x58a2 - 0x589d;
+
+bool CommonReadingTest(Font* raw_font) {
+  FontPtr font = raw_font;
+
+  EblcTablePtr bitmap_loca = down_cast<EblcTable*>(font->GetTable(Tag::EBLC));
+  EbdtTablePtr bitmap_table = down_cast<EbdtTable*>(font->GetTable(Tag::EBDT));
+
+  EXPECT_FALSE(bitmap_loca == NULL);
+  EXPECT_FALSE(bitmap_table == NULL);
+
+  EXPECT_EQ(bitmap_loca->NumSizes(), NUM_STRIKES);
+
+  // Strike 1
+  BitmapSizeTablePtr strike1 = bitmap_loca->GetBitmapSizeTable(0);
+  EXPECT_FALSE(strike1 == NULL);
+  EXPECT_EQ(strike1->IndexSubTableArrayOffset(), STRIKE1_ARRAY_OFFSET);
+  EXPECT_EQ(strike1->NumberOfIndexSubTables(), STRIKE1_NUM_INDEX_TABLES);
+  EXPECT_EQ(strike1->ColorRef(), STRIKE1_COLOR_REF);
+  EXPECT_EQ(strike1->StartGlyphIndex(), STRIKE1_START_GLYPH_INDEX);
+  EXPECT_EQ(strike1->EndGlyphIndex(), STRIKE1_END_GLYPH_INDEX);
+  EXPECT_EQ(strike1->PpemX(), STRIKE1_PPEM_X);
+  EXPECT_EQ(strike1->PpemY(), STRIKE1_PPEM_Y);
+  EXPECT_EQ(strike1->BitDepth(), STRIKE1_BIT_DEPTH);
+  EXPECT_EQ(strike1->FlagsAsInt(), STRIKE1_FLAGS);
+
+  // Strike 4
+  // In this test font, all strikes and all subtables have same glyphs.
+  BitmapSizeTablePtr strike4 = bitmap_loca->GetBitmapSizeTable(3);
+  EXPECT_FALSE(strike4 == NULL);
+  EXPECT_EQ(strike4->StartGlyphIndex(), STRIKE1_START_GLYPH_INDEX);
+  EXPECT_EQ(strike4->EndGlyphIndex(), STRIKE1_END_GLYPH_INDEX);
+  IndexSubTablePtr sub1 = strike4->GetIndexSubTable(0);
+  EXPECT_FALSE(sub1 == NULL);
+  EXPECT_EQ(sub1->image_format(), STRIKE4_SUB1_IMAGE_FORMAT);
+  EXPECT_EQ(sub1->first_glyph_index(), STRIKE1_START_GLYPH_INDEX);
+  EXPECT_EQ(sub1->last_glyph_index(), STRIKE1_END_GLYPH_INDEX);
+  EXPECT_EQ(sub1->image_data_offset(), STRIKE4_SUB1_IMAGE_DATA_OFFSET);
+
+  for (int32_t i = 0; i < NUM_STRIKE4_SUB1_GLYPH_OFFSET; ++i) {
+      EXPECT_EQ(sub1->GlyphOffset(i), STRIKE4_SUB1_GLYPH_OFFSET[i]);
+  }
+  return true;
+}
+
+bool TestReadingBitmapTable() {
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  FontArray font_array;
+  LoadFont(SAMPLE_BITMAP_FONT, factory, &font_array);
+  FontPtr font = font_array[0];
+  EXPECT_TRUE(CommonReadingTest(font));
+
+  EblcTablePtr bitmap_loca = down_cast<EblcTable*>(font->GetTable(Tag::EBLC));
+  BitmapSizeTablePtr strike1 = bitmap_loca->GetBitmapSizeTable(0);
+  BitmapSizeTablePtr strike4 = bitmap_loca->GetBitmapSizeTable(3);
+  IndexSubTablePtr sub1 = strike4->GetIndexSubTable(0);
+
+  EXPECT_EQ(strike1->IndexTableSize(), STRIKE1_INDEX_TABLE_SIZE);
+  EXPECT_EQ(sub1->index_format(), STRIKE4_SUB1_INDEX_FORMAT);
+
+  // Strike 4 Index Sub Table 1 is a Format 3
+  IndexSubTableFormat3Ptr sub3 =
+      down_cast<IndexSubTableFormat3*>(strike4->GetIndexSubTable(0));
+  EXPECT_FALSE(sub3 == NULL);
+  BitmapGlyphInfoPtr info;
+  info.Attach(sub3->GlyphInfo(2));
+  EXPECT_EQ(info->glyph_id(), 2);
+  EXPECT_EQ(info->block_offset(), STRIKE4_SUB1_IMAGE_DATA_OFFSET);
+  EXPECT_EQ(info->start_offset(),
+            STRIKE4_SUB1_GLYPH_OFFSET[2] - STRIKE4_SUB1_GLYPH_OFFSET[0]);
+  EXPECT_EQ(info->format(), STRIKE4_SUB1_IMAGE_FORMAT);
+  EXPECT_EQ(info->length(), STRIKE4_SUB1_GLYPH2_LENGTH);
+
+  return true;
+}
+
+// Function in subset_impl.cc
+extern
+void SubsetEBLC(EblcTable::Builder* eblc, const BitmapLocaList& new_loca);
+
+bool TestIndexFormatConversion() {
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  FontBuilderArray builder_array;
+  BuilderForFontFile(SAMPLE_BITMAP_FONT, factory, &builder_array);
+
+  FontBuilderPtr font_builder;
+  font_builder = builder_array[0];
+  EblcTableBuilderPtr eblc_builder =
+      down_cast<EblcTable::Builder*>(font_builder->GetTableBuilder(Tag::EBLC));
+  BitmapLocaList new_loca;
+  eblc_builder->GenerateLocaList(&new_loca);
+  SubsetEBLC(eblc_builder, new_loca);  // Format 3 -> 4
+
+  FontPtr new_font;
+  new_font.Attach(font_builder->Build());
+
+  // Serialize and reload the serialized font.
+  MemoryOutputStream os;
+  factory->SerializeFont(new_font, &os);
+
+#if defined (SFNTLY_DEBUG_BITMAP)
+  SerializeToFile(&os, "anon-mod.ttf");
+#endif
+
+  MemoryInputStream is;
+  is.Attach(os.Get(), os.Size());
+  FontArray font_array;
+  factory->LoadFonts(&is, &font_array);
+  new_font = font_array[0];
+
+  EXPECT_TRUE(CommonReadingTest(new_font));
+
+  // Strike 4 Index Sub Table 1 is a Format 4
+  EblcTablePtr bitmap_loca =
+      down_cast<EblcTable*>(new_font->GetTable(Tag::EBLC));
+  BitmapSizeTablePtr strike4 = bitmap_loca->GetBitmapSizeTable(3);
+  IndexSubTableFormat4Ptr sub4 =
+      down_cast<IndexSubTableFormat4*>(strike4->GetIndexSubTable(0));
+  EXPECT_FALSE(sub4 == NULL);
+
+  // And this subtable shall have exactly the same offset as original table
+  // since no subsetting happens.
+  FontArray original_font_array;
+  LoadFont(SAMPLE_BITMAP_FONT, factory, &original_font_array);
+  FontPtr font = original_font_array[0];
+  EXPECT_FALSE(font == NULL);
+  EblcTablePtr original_loca = down_cast<EblcTable*>(font->GetTable(Tag::EBLC));
+  EXPECT_FALSE(original_loca == NULL);
+  BitmapSizeTablePtr original_strike4 = bitmap_loca->GetBitmapSizeTable(3);
+  EXPECT_FALSE(original_strike4 == NULL);
+  IndexSubTableFormat3Ptr sub3 =
+      down_cast<IndexSubTableFormat3*>(strike4->GetIndexSubTable(0));
+  EXPECT_FALSE(sub3 == NULL);
+  EXPECT_EQ(strike4->StartGlyphIndex(), original_strike4->StartGlyphIndex());
+  EXPECT_EQ(strike4->EndGlyphIndex(), original_strike4->EndGlyphIndex());
+  for (int32_t i = strike4->StartGlyphIndex();
+               i <= strike4->EndGlyphIndex(); ++i) {
+    BitmapGlyphInfoPtr info, original_info;
+    info.Attach(sub4->GlyphInfo(i));
+    original_info.Attach(sub3->GlyphInfo(i));
+    EXPECT_EQ(info->format(), original_info->format());
+    EXPECT_EQ(info->glyph_id(), original_info->glyph_id());
+    EXPECT_EQ(info->length(), original_info->length());
+    EXPECT_EQ(info->offset(), original_info->offset());
+  }
+
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(BitmapTable, Reading) {
+  ASSERT_TRUE(sfntly::TestReadingBitmapTable());
+}
+
+TEST(BitmapTable, IndexFormatConversion) {
+  ASSERT_TRUE(sfntly::TestIndexFormatConversion());
+}
diff --git a/cpp/src/test/byte_array_test.cc b/cpp/src/test/byte_array_test.cc
new file mode 100644
index 0000000..40a6489
--- /dev/null
+++ b/cpp/src/test/byte_array_test.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include "gtest/gtest.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/data/growable_memory_byte_array.h"
+
+namespace sfntly {
+namespace byte_array_test {
+
+const int32_t BYTE_ARRAY_SIZES[] =
+    {1, 7, 127, 128, 129, 255, 256, 257, 666, 1023, 10000, 0xffff, 0x10000};
+
+void FillTestByteArray(ByteArray* ba, int32_t size) {
+  for (int32_t i = 0; i < size; ++i) {
+    ba->Put(i, (byte_t)(i % 256));
+  }
+}
+
+void ReadByteArrayWithBuffer(ByteArray* ba, ByteVector* buffer, ByteVector* b) {
+  b->resize(ba->Length());
+  int32_t index = 0;
+  while (index < ba->Length()) {
+    int32_t bytes_read = ba->Get(index, buffer);
+    std::copy(buffer->begin(), buffer->begin() + bytes_read,
+              b->begin() + index);
+    index += bytes_read;
+  }
+}
+
+void ReadByteArrayWithSlidingWindow(ByteArray* ba, int window_size,
+                                    ByteVector* b) {
+  b->resize(ba->Length());
+  int32_t index = 0;
+  int32_t actual_window_size = window_size;
+  while (index < ba->Length()) {
+    actual_window_size =
+        std::min<int32_t>(actual_window_size, b->size() - index);
+    int32_t bytes_read = ba->Get(index, &((*b)[0]), index, actual_window_size);
+    index += bytes_read;
+  }
+}
+
+bool ReadComparison(ByteArray* ba1, ByteArray* ba2) {
+  // single byte reads
+  for (int i = 0; i < ba1->Length(); ++i) {
+    EXPECT_EQ(ba1->Get(i), ba2->Get(i));
+  }
+
+  ByteVector b1, b2;
+  // buffer reads
+  int increments = std::max<int32_t>(ba1->Length() / 11, 1);
+  for (int buffer_size = 1; buffer_size < ba1->Length();
+       buffer_size += increments) {
+    ByteVector buffer(buffer_size);
+    ReadByteArrayWithBuffer(ba1, &buffer, &b1);
+    ReadByteArrayWithBuffer(ba2, &buffer, &b2);
+    EXPECT_GT(b1.size(), static_cast<size_t>(0));
+    EXPECT_EQ(b1.size(), b2.size());
+    EXPECT_TRUE(std::equal(b1.begin(), b1.end(), b2.begin()));
+  }
+
+  // sliding window reads
+  b1.clear();
+  b2.clear();
+  for (int window_size = 1; window_size < ba1->Length();
+       window_size += increments) {
+    ReadByteArrayWithSlidingWindow(ba1, window_size, &b1);
+    ReadByteArrayWithSlidingWindow(ba2, window_size, &b2);
+    EXPECT_GT(b1.size(), static_cast<size_t>(0));
+    EXPECT_EQ(b1.size(), b2.size());
+    EXPECT_TRUE(std::equal(b1.begin(), b1.end(), b2.begin()));
+  }
+
+  return true;
+}
+
+bool CopyTest(ByteArray* ba) {
+  ByteArrayPtr fixed_copy = new MemoryByteArray(ba->Length());
+  ba->CopyTo(fixed_copy);
+  EXPECT_EQ(ba->Length(), fixed_copy->Length());
+  EXPECT_TRUE(ReadComparison(ba, fixed_copy));
+
+  ByteArrayPtr growable_copy = new GrowableMemoryByteArray();
+  ba->CopyTo(growable_copy);
+  EXPECT_EQ(ba->Length(), growable_copy->Length());
+  EXPECT_TRUE(ReadComparison(ba, growable_copy));
+
+  return true;
+}
+
+bool ByteArrayTester(ByteArray* ba) {
+  return CopyTest(ba);
+}
+
+}  // namespace byte_array_test
+
+bool TestMemoryByteArray() {
+  fprintf(stderr, "fixed mem: size ");
+  for (size_t i = 0;
+       i < sizeof(byte_array_test::BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) {
+    int32_t size = byte_array_test::BYTE_ARRAY_SIZES[i];
+    fprintf(stderr, "%d ", size);
+    ByteArrayPtr ba = new MemoryByteArray(size);
+    byte_array_test::FillTestByteArray(ba, size);
+    EXPECT_TRUE(byte_array_test::ByteArrayTester(ba));
+  }
+  fprintf(stderr, "\n");
+  return true;
+}
+
+bool TestGrowableMemoryByteArray() {
+  fprintf(stderr, "growable mem: size ");
+  for (size_t i = 0;
+       i < sizeof(byte_array_test::BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) {
+    int32_t size = byte_array_test::BYTE_ARRAY_SIZES[i];
+    fprintf(stderr, "%d ", size);
+    ByteArrayPtr ba = new GrowableMemoryByteArray();
+    byte_array_test::FillTestByteArray(ba, size);
+    EXPECT_TRUE(byte_array_test::ByteArrayTester(ba));
+  }
+  fprintf(stderr, "\n");
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(ByteArray, All) {
+  ASSERT_TRUE(sfntly::TestMemoryByteArray());
+  ASSERT_TRUE(sfntly::TestGrowableMemoryByteArray());
+}
diff --git a/cpp/src/test/chrome_subsetter.cc b/cpp/src/test/chrome_subsetter.cc
new file mode 100644
index 0000000..9563ab1
--- /dev/null
+++ b/cpp/src/test/chrome_subsetter.cc
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sample/chromium/font_subsetter.h"
+#include "test/test_data.h"
+#include "test/test_font_utils.h"
+
+namespace {
+  // Use an additional variable to easily change name for testing.
+  const char* kInputFileName = sfntly::SAMPLE_TTF_FILE;
+  const char* kFontName = "Tuffy";
+  const char* kOutputFileName = "tuffy-s.ttf";
+  // The subset we want: Hello, world!
+  // The array is unsorted to verify that the subsetter gets the glyph id
+  // correctly.
+  const unsigned int kGlyphIds[] = { 43, 72, 79, 82, 15, 3, 90, 85, 71, 4 };
+  const unsigned int kGlyphIdsCount = sizeof(kGlyphIds) / sizeof(unsigned int);
+}
+
+// This function is deliberately located at global namespace.
+bool TestChromeSubsetter() {
+  sfntly::ByteVector input_buffer;
+  sfntly::LoadFile(kInputFileName, &input_buffer);
+  EXPECT_GT(input_buffer.size(), (size_t)0);
+
+  unsigned char* output_buffer = NULL;
+  int output_length =
+      SfntlyWrapper::SubsetFont(kFontName,
+                                &(input_buffer[0]),
+                                input_buffer.size(),
+                                kGlyphIds,
+                                kGlyphIdsCount,
+                                &output_buffer);
+
+  EXPECT_GT(output_length, 0);
+
+  if (output_length > 0) {
+    FILE* output_file = NULL;
+#if defined WIN32
+    fopen_s(&output_file, kOutputFileName, "wb");
+#else
+    output_file = fopen(kOutputFileName, "wb");
+#endif
+    EXPECT_TRUE((output_file != NULL));
+    if (output_file) {
+      int byte_count = fwrite(output_buffer, 1, output_length, output_file);
+      EXPECT_EQ(byte_count, output_length);
+      fflush(output_file);
+      fclose(output_file);
+    }
+
+    delete[] output_buffer;
+    return true;
+  }
+
+  return false;
+}
+
+TEST(ChromeSubsetter, All) {
+  EXPECT_TRUE(TestChromeSubsetter());
+}
diff --git a/cpp/src/test/cmap_editing_test.cc b/cpp/src/test/cmap_editing_test.cc
new file mode 100644
index 0000000..6df2720
--- /dev/null
+++ b/cpp/src/test/cmap_editing_test.cc
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <map>
+#include <algorithm>
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/core/font_header_table.h"
+#include "sfntly/tag.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/port/endian.h"
+#include "sfntly/port/file_input_stream.h"
+#include "sfntly/port/memory_output_stream.h"
+#include "test/test_data.h"
+#include "test/test_font_utils.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/port/refcount.h"
+#include "gtest/gtest.h"
+
+namespace sfntly {
+TEST(CMapEditingTest, RemoveAllButOneCMap) {
+  FontBuilderArray builders;
+  FontFactoryPtr font_factory;
+  font_factory.Attach(FontFactory::GetInstance());
+  BuilderForFontFile(SAMPLE_TTF_FILE, font_factory, &builders);
+  ASSERT_FALSE(builders.empty());
+  FontBuilderPtr font_builder = builders[0];
+  Ptr<CMapTable::Builder> cmap_table_builder =
+      (CMapTable::Builder*)font_builder->GetTableBuilder(Tag::cmap);
+  ASSERT_NE(cmap_table_builder, reinterpret_cast<CMapTable::Builder*>(NULL));
+  CMapTable::CMapBuilderMap*
+      cmap_builders = cmap_table_builder->GetCMapBuilders();
+  ASSERT_FALSE(cmap_builders->empty());
+
+  for (CMapTable::CMapBuilderMap::iterator
+           it = cmap_builders->begin(); it != cmap_builders->end();) {
+    if (it->second->cmap_id() == CMapTable::WINDOWS_BMP) {
+      ++it;
+    } else {
+      cmap_builders->erase(it++);
+    }
+  }
+  ASSERT_EQ(cmap_builders->size(), (uint32_t)1);
+  Font* font = font_builder->Build();
+  CMapTablePtr cmap_table = down_cast<CMapTable*>(font->GetTable(Tag::cmap));
+  ASSERT_EQ(1, cmap_table->NumCMaps());
+  CMapTable::CMapPtr cmap;
+  cmap.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP));
+  ASSERT_EQ(CMapTable::WINDOWS_BMP, cmap->cmap_id());
+  delete font;
+}
+
+TEST(CMapEditingTest, CopyAllCMapsToNewFont) {
+  FontArray fonts;
+  FontFactoryPtr font_factory;
+  font_factory.Attach(FontFactory::GetInstance());
+  LoadFont(SAMPLE_TTF_FILE, font_factory, &fonts);
+
+  ASSERT_FALSE(fonts.empty());
+  ASSERT_FALSE(fonts[0] == NULL);
+  FontPtr font = fonts[0];
+  CMapTablePtr cmap_table = down_cast<CMapTable*>(font->GetTable(Tag::cmap));
+  FontBuilderPtr font_builder;
+  font_builder.Attach(font_factory->NewFontBuilder());
+  Ptr<CMapTable::Builder> cmap_table_builder =
+      (CMapTable::Builder*)font_builder->NewTableBuilder(Tag::cmap);
+
+  CMapTable::CMapIterator cmap_iter(cmap_table, NULL);
+  while (cmap_iter.HasNext()) {
+    CMapTable::CMapPtr cmap;
+    cmap.Attach(cmap_iter.Next());
+    if (!cmap)
+      continue;
+    cmap_table_builder->NewCMapBuilder(cmap->cmap_id(), cmap->ReadFontData());
+  }
+
+  FontPtr new_font;
+  new_font.Attach(font_builder->Build());
+  CMapTablePtr new_cmap_table =
+      down_cast<CMapTable*>(font->GetTable(Tag::cmap));
+  ASSERT_EQ(cmap_table->NumCMaps(), new_cmap_table->NumCMaps());
+  CMapTable::CMapPtr cmap;
+  cmap.Attach(cmap_table->GetCMap(CMapTable::WINDOWS_BMP));
+  ASSERT_NE(cmap, reinterpret_cast<CMapTable::CMap*>(NULL));
+  ASSERT_EQ(CMapTable::WINDOWS_BMP, cmap->cmap_id());
+}
+}
diff --git a/cpp/src/test/cmap_iterator_test.cc b/cpp/src/test/cmap_iterator_test.cc
new file mode 100644
index 0000000..2e8e6fe
--- /dev/null
+++ b/cpp/src/test/cmap_iterator_test.cc
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+
+#include <vector>
+#include <string>
+#include <algorithm>
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/tag.h"
+#include "sfntly/port/type.h"
+#include "sfntly/port/refcount.h"
+#include "test/test_data.h"
+#include "test/test_font_utils.h"
+
+#include "gtest/gtest.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace sfntly {
+using ::testing::TestWithParam;
+using ::testing::Values;
+
+typedef std::vector<bool> BitSet;
+
+class CMapIteratorTestCase {
+ public:
+  CMapIteratorTestCase(int32_t platform_id, int32_t encoding_id,
+                       const char* file_name)
+      : platform_id_(platform_id),
+        encoding_id_(encoding_id),
+        file_name_(file_name) {
+  }
+  ~CMapIteratorTestCase() {}
+  int32_t platform_id() const { return platform_id_; }
+  int32_t encoding_id() const { return encoding_id_; }
+  const char* file_name() const { return file_name_; }
+
+ private:
+  int32_t platform_id_;
+  int32_t encoding_id_;
+  const char* file_name_;
+};
+
+class CMapIteratorTests
+    : public ::testing::TestWithParam<CMapIteratorTestCase> {
+ public:
+  virtual void SetUp();
+  virtual void TearDown() {}
+
+  BitSet* GenerateCMapEntries(int32_t start, int32_t count);
+  int32_t CompareCMapIterAndBitSet(CMapTable::CMap::CharacterIterator*
+                                   character_iterator,
+                                   BitSet* bit_set);
+
+  Ptr<CMapTable::CMap> cmap_;
+};
+
+void CMapIteratorTests::SetUp() {
+  FontArray fonts;
+  Ptr<FontFactory> font_factory;
+  const char* file_name = GetParam().file_name();
+  LoadFont(file_name, font_factory, &fonts);
+  Ptr<Font> font;
+  font.Attach(fonts[0].Detach());
+  Ptr<CMapTable> cmap_table = down_cast<CMapTable*>(font->GetTable(Tag::cmap));
+  ASSERT_FALSE(cmap_table == NULL);
+  cmap_.Attach(cmap_table->GetCMap(GetParam().platform_id(),
+                                   GetParam().encoding_id()));
+  ASSERT_FALSE(cmap_ == NULL);
+}
+
+BitSet* CMapIteratorTests::GenerateCMapEntries(int32_t start, int32_t count) {
+  BitSet* entries = new BitSet(count);
+  for (int32_t c = start; c < start + count; ++c) {
+    int32_t g = cmap_->GlyphId(c);
+    if (g != CMapTable::NOTDEF)
+      (*entries)[c] = true;
+  }
+  return entries;
+}
+
+int32_t
+CMapIteratorTests::
+CompareCMapIterAndBitSet(CMapTable::CMap::CharacterIterator* character_iterator,
+                         BitSet* bit_set) {
+  int32_t iterator_not_bitset_count = 0;
+  BitSet::iterator end = bit_set->end(),
+      beginning = bit_set->begin(),
+      init_beginning = beginning,
+      current = std::find(beginning, end, true);
+  for (int32_t next_bit = current - beginning;
+       character_iterator->HasNext() && current != end;
+       next_bit = current - init_beginning) {
+    int32_t c = character_iterator->Next();
+    EXPECT_TRUE(c <= next_bit || current == end);
+    if (!(c <= next_bit || current == end))
+      return -1;
+    if (c == next_bit) {
+      beginning = current + 1;
+      current = std::find(beginning, end, true);
+    } else {
+      iterator_not_bitset_count++;
+    }
+  }
+  EXPECT_EQ(end, current);
+#if defined (SFNTLY_DEBUG_CMAP)
+  fprintf(stderr, "%s %d: Differences between iterator and bitset: %d\n",
+          cmap_->format(), GetParam().file_name(), iterator_not_bitset_count);
+#endif
+  return iterator_not_bitset_count;
+}
+
+TEST_P(CMapIteratorTests, IteratorTest) {
+  BitSet* bit_set = GenerateCMapEntries(0, 0x10ffff);
+  CMapTable::CMap::CharacterIterator* character_iterator = NULL;
+  character_iterator = cmap_->Iterator();
+  EXPECT_NE(character_iterator,
+            reinterpret_cast<CMapTable::CMap::CharacterIterator*>(NULL));
+  CompareCMapIterAndBitSet(character_iterator, bit_set);
+  delete character_iterator;
+  delete bit_set;
+}
+
+CMapIteratorTestCase kCMapIteratorTestsTestCases[] = {
+  CMapIteratorTestCase(CMapTable::WINDOWS_BMP.platform_id,
+                       CMapTable::WINDOWS_BMP.encoding_id,
+                       SAMPLE_TTF_FILE)
+};
+
+INSTANTIATE_TEST_CASE_P(CMapIteratorTests,
+                        CMapIteratorTests,
+                        ::testing::ValuesIn(kCMapIteratorTestsTestCases));
+}
+
+#else
+
+TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
+
+#endif  // GTEST_HAS_PARAM
diff --git a/cpp/src/test/cmap_test.cc b/cpp/src/test/cmap_test.cc
new file mode 100644
index 0000000..02bf8a2
--- /dev/null
+++ b/cpp/src/test/cmap_test.cc
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/port/type.h"
+#include <assert.h>
+#include <unicode/ucnv.h>
+
+#include <string>
+#include <iostream>
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/core/cmap_table.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/table/core/font_header_table.h"
+#include "sfntly/tag.h"
+
+#include "test/test_utils.h"
+#include "test/test_font_utils.h"
+#include "test/test_data.h"
+
+#if GTEST_HAS_PARAM_TEST
+
+namespace sfntly {
+using ::testing::TestWithParam;
+using ::testing::Values;
+
+class CMapTestCase {
+ public:
+  CMapTestCase(const char* font_name,
+               int32_t first_platform_id,
+               int32_t first_encoding_id,
+               const char* first_charset_name,
+               int32_t second_platform_id,
+               int32_t second_encoding_id,
+               const char* second_charset_name,
+               int32_t low_char,
+               int32_t high_char)
+      : font_name_(font_name),
+        first_platform_id_(first_platform_id),
+        first_encoding_id_(first_encoding_id),
+        first_charset_name_(first_charset_name),
+        second_platform_id_(second_platform_id),
+        second_encoding_id_(second_encoding_id),
+        second_charset_name_(second_charset_name),
+        low_char_(low_char),
+        high_char_(high_char) {
+  }
+
+  const char* font_name() const { return font_name_; }
+  int32_t first_platform_id() const { return first_platform_id_; }
+  int32_t first_encoding_id() const { return first_encoding_id_; }
+  const char* first_charset_name() const { return first_charset_name_; }
+  int32_t second_platform_id() const { return second_platform_id_; }
+  int32_t second_encoding_id() const { return second_encoding_id_; }
+  const char* second_charset_name() const { return second_charset_name_; }
+  int32_t low_char() const { return low_char_; }
+  int32_t high_char() const { return high_char_; }
+
+ private:
+  const char* font_name_;
+  int32_t first_platform_id_;
+  int32_t first_encoding_id_;
+  const char* first_charset_name_;
+  int32_t second_platform_id_;
+  int32_t second_encoding_id_;
+  const char* second_charset_name_;
+  int32_t low_char_;
+  int32_t high_char_;
+};
+
+class CMapTests : public :: testing::TestWithParam<CMapTestCase> {
+ public:
+  CMapTests() : encoder1_(NULL), encoder2_(NULL), successful_setup_(false) {
+  }
+  virtual void SetUp() {}
+  virtual void TearDown();
+
+  void CommonSetUp(FontArray* font_array);
+
+  void CompareCMaps();
+
+  Ptr<CMapTable::CMap> cmap1_;
+  Ptr<CMapTable::CMap> cmap2_;
+  UConverter* encoder1_;
+  UConverter* encoder2_;
+  bool successful_setup_;
+};
+
+::std::ostream& operator<<(::std::ostream& os, const CMapTestCase *test_case) {
+  return os << "("
+            << test_case->font_name() << ", "
+            << test_case->first_platform_id() << ", "
+            << test_case->first_encoding_id() << ", "
+            << test_case->first_charset_name() << ", "
+            << test_case->second_platform_id() << ", "
+            << test_case->second_encoding_id() << ", "
+            << test_case->second_charset_name() << ", "
+            << test_case->low_char() << ", "
+            << test_case->high_char() << ")";
+}
+
+void CMapTests::CommonSetUp(FontArray* font_array) {
+  ASSERT_NE(font_array, reinterpret_cast<FontArray*>(NULL));
+  ASSERT_FALSE(font_array->empty());
+  Ptr<Font> font;
+  font = font_array->at(0);
+  ASSERT_NE(font, reinterpret_cast<Font*>(NULL));
+  Ptr<CMapTable> cmap_table =
+      down_cast<CMapTable*>(font->GetTable(Tag::cmap));
+  cmap1_.Attach(cmap_table->GetCMap(GetParam().first_platform_id(),
+                                    GetParam().first_encoding_id()));
+  ASSERT_NE((cmap1_), reinterpret_cast<CMapTable::CMap*>(NULL));
+  cmap2_.Attach(cmap_table->GetCMap(GetParam().second_platform_id(),
+                                    GetParam().second_encoding_id()));
+  ASSERT_NE((cmap2_), reinterpret_cast<CMapTable::CMap*>(NULL));
+  encoder1_ = TestUtils::GetEncoder(GetParam().first_charset_name());
+  encoder2_ = TestUtils::GetEncoder(GetParam().second_charset_name());
+  successful_setup_ = true;
+}
+
+void CMapTests::TearDown() {
+  if (encoder1_)
+    ucnv_close(encoder1_);
+  if (encoder2_)
+    ucnv_close(encoder2_);
+}
+
+void CMapTests::CompareCMaps() {
+  ASSERT_TRUE(successful_setup_);
+  for (int32_t uchar = GetParam().low_char();
+       uchar <= GetParam().high_char(); ++uchar) {
+    int32_t c1 = uchar;
+    if (encoder1_ != NULL)
+      c1 = TestUtils::EncodeOneChar(encoder1_, (int16_t)uchar);
+    int32_t c2 = uchar;
+    if (encoder2_ != NULL)
+      c2 = TestUtils::EncodeOneChar(encoder2_, (int16_t)uchar);
+    int32_t glyph_id1 = cmap1_->GlyphId(c1);
+    int32_t glyph_id2 = cmap2_->GlyphId(c2);
+#ifdef SFNTLY_DEBUG_CMAP
+    if (glyph_id1 != glyph_id2)
+      fprintf(stderr, "%x: g1=%x, %x: g2=%x\n", c1, glyph_id1, c2, glyph_id2);
+#endif
+    ASSERT_EQ(glyph_id1, glyph_id2);
+  }
+#ifdef SFNTLY_SFNTLY_DEBUG_CMAPCMAP
+  fprintf(stderr, "\n");
+#endif
+}
+
+TEST_P(CMapTests, GlyphsBetweenCMapsFingerprint) {
+  Ptr<FontFactory> font_factory;
+  font_factory.Attach(FontFactory::GetInstance());
+  font_factory->FingerprintFont(true);
+  FontArray font_array;
+  LoadFont(GetParam().font_name(), font_factory, &font_array);
+  CommonSetUp(&font_array);
+  CompareCMaps();
+}
+
+TEST_P(CMapTests, GlyphsBetweenCMapsNoFingerprint) {
+  Ptr<FontFactory> font_factory;
+  font_factory.Attach(FontFactory::GetInstance());
+  FontArray font_array;
+  LoadFont(GetParam().font_name(), font_factory, &font_array);
+  CommonSetUp(&font_array);
+  CompareCMaps();
+}
+
+TEST_P(CMapTests, GlyphsBetweenCMapsUsingByteVector) {
+  FontArray font_array;
+  LoadFontUsingByteVector(GetParam().font_name(), true, &font_array);
+  CommonSetUp(&font_array);
+  CompareCMaps();
+}
+
+CMapTestCase kCMapTestsTestCases[] = {
+  CMapTestCase(SAMPLE_TTF_FILE,
+               PlatformId::kWindows,
+               WindowsEncodingId::kUnicodeUCS2,
+               NULL,
+               PlatformId::kUnicode,
+               UnicodeEncodingId::kUnicode2_0_BMP,
+               NULL,
+               (int32_t)0x20,
+               (int32_t)0x7f),
+};
+
+INSTANTIATE_TEST_CASE_P(CMapTests,
+                        CMapTests,
+                        ::testing::ValuesIn(kCMapTestsTestCases));
+}
+
+#else
+
+TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
+
+#endif  // GTEST_HAS_PARAM
diff --git a/cpp/src/test/endian_test.cc b/cpp/src/test/endian_test.cc
new file mode 100644
index 0000000..0d9da09
--- /dev/null
+++ b/cpp/src/test/endian_test.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/tag.h"
+#include "sfntly/data/growable_memory_byte_array.h"
+#include "sfntly/data/writable_font_data.h"
+#include "sfntly/math/fixed1616.h"
+#include "sfntly/port/memory_output_stream.h"
+#include "sfntly/data/font_output_stream.h"
+
+namespace sfntly {
+
+bool TestEndian() {
+  byte_t test_data[] = {
+      0x68, 0x65, 0x61, 0x64,  // 0: head
+      0xca, 0xca, 0xca, 0xca,  // 4: ubyte, byte, char
+      0x00, 0x18, 0x80, 0x18,  // 8: ushort, short
+      0x00, 0x00, 0x18, 0x00,  // 12: uint24
+      0x00, 0x00, 0x00, 0x18,  // 16: ulong
+      0xff, 0xff, 0xff, 0x00,  // 20: long
+      0x00, 0x01, 0x00, 0x00   // 24: fixed
+  };
+
+  ByteArrayPtr ba1 = new GrowableMemoryByteArray();
+  for (size_t i = 0; i < sizeof(test_data); ++i) {
+    ba1->Put(i, test_data[i]);
+  }
+  ReadableFontDataPtr rfd = new ReadableFontData(ba1);
+  EXPECT_EQ(rfd->ReadULongAsInt(0), Tag::head);
+  EXPECT_EQ(rfd->ReadUByte(4), 202);
+  EXPECT_EQ(rfd->ReadByte(5), -54);
+  EXPECT_EQ(rfd->ReadChar(6), 202);
+  EXPECT_EQ(rfd->ReadUShort(8), 24);
+  EXPECT_EQ(rfd->ReadShort(10), -32744);
+  EXPECT_EQ(rfd->ReadUInt24(12), 24);
+  EXPECT_EQ(rfd->ReadULong(16), 24);
+  EXPECT_EQ(rfd->ReadLong(20), -256);
+  EXPECT_EQ(rfd->ReadFixed(24), Fixed1616::Fixed(1, 0));
+
+  MemoryOutputStream os;
+  FontOutputStream fos(&os);
+  fos.WriteULong(Tag::head);
+  fos.Write(202);
+  fos.Write(202);
+  fos.Write(202);
+  fos.Write(202);
+  fos.WriteUShort(24);
+  fos.WriteShort(-32744);
+  fos.WriteUInt24(24);
+  fos.WriteChar(0);
+  fos.WriteULong(24);
+  fos.WriteLong(-256);
+  fos.WriteFixed(Fixed1616::Fixed(1, 0));
+  EXPECT_EQ(memcmp(os.Get(), test_data, sizeof(test_data)), 0);
+
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(Endian, All) {
+  ASSERT_TRUE(sfntly::TestEndian());
+}
diff --git a/cpp/src/test/file_io_test.cc b/cpp/src/test/file_io_test.cc
new file mode 100644
index 0000000..3cec4d6
--- /dev/null
+++ b/cpp/src/test/file_io_test.cc
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include "gtest/gtest.h"
+#include "sfntly/port/file_input_stream.h"
+#include "sfntly/data/font_input_stream.h"
+#include "test/test_data.h"
+
+namespace sfntly {
+
+bool TestFileInputStream() {
+  FILE* file_handle = NULL;
+#if defined (WIN32)
+  fopen_s(&file_handle, SAMPLE_TTF_FILE, "rb");
+#else
+  file_handle = fopen(SAMPLE_TTF_FILE, "rb");
+#endif
+  if (file_handle == NULL) {
+    return false;
+  }
+  fseek(file_handle, 0, SEEK_END);
+  size_t length = ftell(file_handle);
+  fseek(file_handle, 0, SEEK_SET);
+  ByteVector b1;
+  b1.resize(length);
+  size_t bytes_read = fread(&(b1[0]), 1, length, file_handle);
+  EXPECT_EQ(bytes_read, length);
+  fclose(file_handle);
+
+  // Full file reading test
+  FileInputStream is;
+  is.Open(SAMPLE_TTF_FILE);
+  EXPECT_EQ(length, (size_t)is.Available());
+  ByteVector b2;
+  is.Read(&b2, 0, length);
+  is.Close();
+  EXPECT_EQ(memcmp(&(b1[0]), &(b2[0]), length), 0);
+  b2.clear();
+
+  // Partial reading test
+  is.Open(SAMPLE_TTF_FILE);
+  is.Skip(89);
+  is.Read(&b2, 0, 100);
+  EXPECT_EQ(memcmp(&(b1[89]), &(b2[0]), 100), 0);
+  b2.clear();
+
+  // Skip test
+  is.Skip(-89);
+  is.Read(&b2, 0, 100);
+  EXPECT_EQ(memcmp(&(b1[100]), &(b2[0]), 100), 0);
+  b2.clear();
+  is.Skip(100);
+  is.Read(&b2, 0, 100);
+  EXPECT_EQ(memcmp(&(b1[300]), &(b2[0]), 100), 0);
+  is.Skip(-400);
+  b2.clear();
+
+  // Offset test
+  is.Read(&b2, 0, 100);
+  is.Read(&b2, 100, 100);
+  EXPECT_EQ(memcmp(&(b1[0]), &(b2[0]), 200), 0);
+
+  // Unread test
+  ByteVector b3;
+  b3.resize(200);
+  is.Unread(&b3);
+  EXPECT_EQ(memcmp(&(b3[0]), &(b2[0]), 200), 0);
+
+  return true;
+}
+
+bool TestFontInputStreamBasic() {
+  FILE* file_handle = NULL;
+#if defined (WIN32)
+  fopen_s(&file_handle, SAMPLE_TTF_FILE, "rb");
+#else
+  file_handle = fopen(SAMPLE_TTF_FILE, "rb");
+#endif
+  if (file_handle == NULL) {
+    return false;
+  }
+  fseek(file_handle, 0, SEEK_END);
+  size_t length = ftell(file_handle);
+  fseek(file_handle, 0, SEEK_SET);
+  ByteVector b1;
+  b1.resize(length);
+  size_t bytes_read = fread(&(b1[0]), 1, length, file_handle);
+  EXPECT_EQ(bytes_read, length);
+  fclose(file_handle);
+
+  FileInputStream is;
+  is.Open(SAMPLE_TTF_FILE);
+  FontInputStream font_is1(&is);
+  EXPECT_EQ((size_t)font_is1.Available(), length);
+
+  ByteVector b2;
+  font_is1.Read(&b2, 0, length);
+  font_is1.Close();
+  EXPECT_EQ(memcmp(&(b1[0]), &(b2[0]), length), 0);
+  b2.clear();
+
+  is.Open(SAMPLE_TTF_FILE);
+  is.Skip(89);
+  FontInputStream font_is2(&is, 200);
+  font_is2.Read(&b2, 0, 100);
+  EXPECT_EQ(memcmp(&(b1[89]), &(b2[0]), 100), 0);
+  font_is2.Read(&b2, 100, 100);
+  EXPECT_EQ(memcmp(&(b1[89]), &(b2[0]), 200), 0);
+  b2.clear();
+  font_is2.Skip(-200);
+  font_is2.Read(&b2, 0, 100);
+  EXPECT_EQ(memcmp(&(b1[89]), &(b2[0]), 100), 0);
+
+  return true;
+}
+
+bool TestFontInputStreamTableLoading() {
+  FileInputStream is;
+  is.Open(SAMPLE_TTF_FILE);
+  FontInputStream font_is(&is);
+
+  font_is.Skip(TTF_OFFSET[SAMPLE_TTF_FEAT]);
+  FontInputStream gdef_is(&font_is, TTF_LENGTH[SAMPLE_TTF_FEAT]);
+  ByteVector feat_data;
+  gdef_is.Read(&feat_data, 0, TTF_LENGTH[SAMPLE_TTF_FEAT]);
+  EXPECT_EQ(memcmp(&(feat_data[0]), TTF_FEAT_DATA,
+                   TTF_LENGTH[SAMPLE_TTF_FEAT]), 0);
+
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(FileIO, All) {
+  ASSERT_TRUE(sfntly::TestFileInputStream());
+  ASSERT_TRUE(sfntly::TestFontInputStreamBasic());
+  ASSERT_TRUE(sfntly::TestFontInputStreamTableLoading());
+}
diff --git a/cpp/src/test/font_data_test.cc b/cpp/src/test/font_data_test.cc
new file mode 100644
index 0000000..4b0db64
--- /dev/null
+++ b/cpp/src/test/font_data_test.cc
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vector>
+#include <algorithm>
+
+#include "gtest/gtest.h"
+#include "sfntly/port/type.h"
+#include "sfntly/data/writable_font_data.h"
+#include "sfntly/data/memory_byte_array.h"
+
+namespace sfntly {
+
+const int32_t BYTE_ARRAY_SIZES[] =
+  {1, 7, 127, 128, 129, 255, 256, 257, 666, 1023, 0x10000};
+
+// array data for searching
+const int32_t LOWER_BYTE_ARRAY_FOR_SEARCHING[] = {2, 4, 7, 13, 127};
+const int32_t UPPER_BYTE_ARRAY_FOR_SEARCHING[] = {2, 5, 12, 16, 256};
+const int32_t kLowerByteArrayForSearchingLength = 5;
+const int32_t kUpperByteArrayForSearchingLength = 5;
+
+// search test result pairs - number to search for; index found at
+const int32_t SEARCH_TEST_PAIRS[][2] = {
+  {0, -1}, {1, -1}, {2, 0}, {3, -1}, {4, 1}, {5, 1}, {6, -1}, {12, 2},
+  {13, 3}, {17, -1}, {126, -1}, {127, 4}, {256, 4}, {257, -1}, {0x1000, -1}
+};
+const int32_t kSearchTestPairsLength = 15;
+
+// offset and start index data for searching data
+// array data size, lower_start_index, lower_offset, upper_start_index,
+// upper_offset
+const int32_t SEARCH_TEST_OFFSETS[][5] = {
+  // lower[], upper[]
+  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
+    * DataSize::kUSHORT,
+    0,
+    DataSize::kUSHORT,
+    kLowerByteArrayForSearchingLength * DataSize::kUSHORT,
+    DataSize::kUSHORT },
+
+  // {lower, upper} []
+  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
+    * DataSize::kUSHORT,
+    0,
+    2 * DataSize::kUSHORT,
+    DataSize::kUSHORT,
+    2 * DataSize::kUSHORT },
+
+  // upper[], lower[]
+  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
+    * DataSize::kUSHORT,
+    kLowerByteArrayForSearchingLength * DataSize::kUSHORT,
+    DataSize::kUSHORT,
+    0,
+    DataSize::kUSHORT },
+
+  // {upper, lower} []
+  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
+    * DataSize::kUSHORT,
+    DataSize::kUSHORT,
+    2 * DataSize::kUSHORT,
+    0,
+    2 * DataSize::kUSHORT }
+};
+const int32_t kSearchTestOffsetLength = 4;
+
+ReadableFontData*
+FillTestFontDataWithShortsForSearching(WritableFontData* wfd,
+                                       const int32_t* lower_data,
+                                       int32_t lower_start_index,
+                                       int32_t lower_offset,
+                                       const int32_t* upper_data,
+                                       int32_t upper_start_index,
+                                       int32_t upper_offset) {
+  // lower data
+  int offset = lower_start_index;
+  for (int32_t i = 0; i < kLowerByteArrayForSearchingLength; ++i) {
+    wfd->WriteUShort(offset, lower_data[i]);
+    offset += lower_offset;
+  }
+
+  // upper data
+  offset = upper_start_index;
+  for (int32_t i = 0; i < kUpperByteArrayForSearchingLength; ++i) {
+    wfd->WriteUShort(offset, upper_data[i]);
+    offset += upper_offset;
+  }
+
+  return wfd;
+}
+
+bool TestReadableFontDataSearching() {
+  for (int32_t i = 0; i < kSearchTestOffsetLength; ++i) {
+    const int32_t* array_setup_offset = SEARCH_TEST_OFFSETS[i];
+    WritableFontDataPtr wfd;
+    wfd.Attach(WritableFontData::CreateWritableFontData(array_setup_offset[0]));
+    FillTestFontDataWithShortsForSearching(wfd,
+                                           LOWER_BYTE_ARRAY_FOR_SEARCHING,
+                                           array_setup_offset[1],
+                                           array_setup_offset[2],
+                                           UPPER_BYTE_ARRAY_FOR_SEARCHING,
+                                           array_setup_offset[3],
+                                           array_setup_offset[4]);
+    for (int32_t j = 0; j < kSearchTestPairsLength; ++j) {
+      const int32_t* test_case = SEARCH_TEST_PAIRS[j];
+      int32_t found = wfd->SearchUShort(array_setup_offset[1],
+                                        array_setup_offset[2],
+                                        array_setup_offset[3],
+                                        array_setup_offset[4],
+                                        kLowerByteArrayForSearchingLength,
+                                        test_case[0]);
+#if defined (SFNTLY_DEBUG_FONTDATA)
+      fprintf(stderr, "Searching for %d; Got %d; Expected %d; "
+              "[test %d][offset %d]\n",
+              test_case[0], found, test_case[1], j, i);
+#endif
+      EXPECT_EQ(test_case[1], found);
+    }
+  }
+  return true;
+}
+
+void FillTestByteArray(ByteArray* ba, int32_t size) {
+  for (int32_t i = 0; i < size; ++i) {
+    ba->Put(i, (byte_t)(i % 256));
+  }
+}
+
+void ReadFontDataWithSingleByte(ReadableFontData* rfd, ByteVector* buffer) {
+  buffer->resize(rfd->Length());
+  for (int32_t index = 0; index < rfd->Length(); ++index) {
+    (*buffer)[index] = (byte_t)(rfd->ReadByte(index));
+  }
+}
+
+void ReadFontDataWithBuffer(ReadableFontData* rfd,
+                            int32_t buffer_size,
+                            ByteVector* b) {
+  ByteVector buffer(buffer_size);
+  b->resize(rfd->Length());
+
+  int32_t index = 0;
+  while (index < rfd->Length()) {
+    int32_t bytes_read = rfd->ReadBytes(index, &(buffer[0]), 0, buffer.size());
+    EXPECT_GE(bytes_read, 0);
+    std::copy(buffer.begin(), buffer.begin() + bytes_read, b->begin() + index);
+    index += bytes_read;
+  }
+}
+
+void ReadFontDataWithSlidingWindow(ReadableFontData* rfd, int32_t window_size,
+                                   ByteVector* b) {
+  b->resize(rfd->Length());
+  int32_t index = 0;
+  while (index < rfd->Length()) {
+    int32_t actual_window_size =
+        std::min<int32_t>(window_size, b->size() - index);
+    int32_t bytes_read =
+        rfd->ReadBytes(index, &((*b)[0]), index, actual_window_size);
+    EXPECT_GE(bytes_read, 0);
+    index += bytes_read;
+  }
+}
+
+void WriteFontDataWithSingleByte(ReadableFontData* rfd, WritableFontData* wfd) {
+  for (int32_t index = 0; index < rfd->Length(); ++index) {
+    byte_t b = (byte_t)(rfd->ReadByte(index));
+    wfd->WriteByte(index, b);
+  }
+}
+
+void WriteFontDataWithBuffer(ReadableFontData* rfd,
+                             WritableFontData* wfd,
+                             int32_t buffer_size) {
+  ByteVector buffer(buffer_size);
+  int32_t index = 0;
+  while (index < rfd->Length()) {
+    int32_t bytesRead = rfd->ReadBytes(index, &(buffer[0]), 0, buffer.size());
+    wfd->WriteBytes(index, &(buffer[0]), 0, buffer.size());
+    index += bytesRead;
+  }
+}
+
+void WriteFontDataWithSlidingWindow(ReadableFontData* rfd,
+                                    WritableFontData* wfd,
+                                    int32_t window_size) {
+  ByteVector b(rfd->Length());
+  int32_t index = 0;
+  while (index < rfd->Length()) {
+    int32_t sliding_size = std::min<int32_t>(window_size, b.size() - index);
+    int32_t bytes_read = rfd->ReadBytes(index, &(b[0]), index, sliding_size);
+    wfd->WriteBytes(index, &(b[0]), index, sliding_size);
+    index += bytes_read;
+  }
+}
+
+bool ReadComparison(int32_t offset,
+                    int32_t length,
+                    ReadableFontData* rfd1,
+                    ReadableFontData* rfd2) {
+  EXPECT_TRUE(length == rfd2->Length());
+  ByteVector b1, b2;
+  b1.resize(length);
+  b2.resize(length);
+
+  // single byte reads
+  ReadFontDataWithSingleByte(rfd1, &b1);
+  ReadFontDataWithSingleByte(rfd2, &b2);
+  EXPECT_EQ(memcmp(&(b1[offset]), &(b2[0]), length), 0);
+
+  // buffer reads
+  int32_t increments = std::max<int32_t>(length / 11, 1);
+  for (int32_t buffer_size = 1; buffer_size <= length;
+       buffer_size += increments) {
+    b1.clear();
+    b2.clear();
+    b1.resize(length);
+    b2.resize(length);
+    ReadFontDataWithBuffer(rfd1, buffer_size, &b1);
+    ReadFontDataWithBuffer(rfd2, buffer_size, &b2);
+    int result = memcmp(&(b1[offset]), &(b2[0]), length);
+    EXPECT_EQ(result, 0);
+  }
+
+  // sliding window reads
+  for (int32_t window_size = 1; window_size <= length;
+       window_size += increments) {
+    b1.clear();
+    b2.clear();
+    b1.resize(length);
+    b2.resize(length);
+    ReadFontDataWithSlidingWindow(rfd1, window_size, &b1);
+    ReadFontDataWithSlidingWindow(rfd2, window_size, &b2);
+    int result = memcmp(&(b1[offset]), &(b2[0]), length);
+    EXPECT_EQ(result, 0);
+  }
+  return true;
+}
+
+void SlicingReadTest(ReadableFontData* rfd) {
+  fprintf(stderr, "read - trim = ");
+  for (int32_t trim = 0; trim < (rfd->Length() / 2) + 1;
+       trim += (rfd->Length() / 21) + 1) {
+    fprintf(stderr, "%d ", trim);
+    int32_t length = rfd->Length() - 2 * trim;
+    ReadableFontDataPtr slice;
+    slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
+    EXPECT_TRUE(ReadComparison(trim, length, rfd, slice));
+  }
+  fprintf(stderr, "\n");
+}
+
+void SlicingWriteTest(ReadableFontData* rfd, WritableFontData* wfd) {
+  fprintf(stderr, "write - trim = ");
+  for (int32_t trim = 0; trim < (rfd->Length() / 2) + 1;
+       trim += (rfd->Length() / 21) + 1) {
+    fprintf(stderr, "%d ", trim);
+    int32_t length = rfd->Length() - 2 * trim;
+    WritableFontDataPtr w_slice;
+    ReadableFontDataPtr r_slice;
+
+    // single byte writes
+    w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length)));
+    r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
+    WriteFontDataWithSingleByte(r_slice, w_slice);
+    EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice));
+
+    // buffer writes
+    int32_t increments = std::max<int32_t>(length / 11, 1);
+    for (int32_t buffer_size = 1; buffer_size < length;
+         buffer_size += increments) {
+      w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length)));
+      r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
+      WriteFontDataWithBuffer(r_slice, w_slice, buffer_size);
+      EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice));
+    }
+
+    // sliding window writes
+    for (int window_size = 1; window_size < length; window_size += increments) {
+      w_slice.Attach(down_cast<WritableFontData*>(wfd->Slice(trim, length)));
+      r_slice.Attach(down_cast<ReadableFontData*>(rfd->Slice(trim, length)));
+      WriteFontDataWithSlidingWindow(r_slice, w_slice, window_size);
+      EXPECT_TRUE(ReadComparison(trim, length, rfd, w_slice));
+    }
+  }
+  fprintf(stderr, "\n");
+}
+
+bool TestReadableFontData() {
+  for (size_t i = 0; i < sizeof(BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) {
+    int32_t size = BYTE_ARRAY_SIZES[i];
+    ByteArrayPtr ba = new MemoryByteArray(size);
+    FillTestByteArray(ba, size);
+    ReadableFontDataPtr rfd = new ReadableFontData(ba);
+    SlicingReadTest(rfd);
+  }
+  return true;
+}
+
+bool TestWritableFontData() {
+  for (size_t i = 0; i < sizeof(BYTE_ARRAY_SIZES) / sizeof(int32_t); ++i) {
+    int32_t size = BYTE_ARRAY_SIZES[i];
+    ByteArrayPtr ba = new MemoryByteArray(size);
+    FillTestByteArray(ba, size);
+    WritableFontDataPtr wfd = new WritableFontData(ba);
+    SlicingReadTest(wfd);
+    ByteArrayPtr temp = new MemoryByteArray(size);
+    WritableFontDataPtr wfd_copy = new WritableFontData(temp);
+    SlicingWriteTest(wfd, wfd_copy);
+  }
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(FontData, ReadableFontDataSearching) {
+  ASSERT_TRUE(sfntly::TestReadableFontDataSearching());
+}
+
+TEST(FontData, All) {
+  ASSERT_TRUE(sfntly::TestReadableFontData());
+  ASSERT_TRUE(sfntly::TestWritableFontData());
+}
diff --git a/cpp/src/test/font_parsing_test.cc b/cpp/src/test/font_parsing_test.cc
new file mode 100644
index 0000000..6fd5c3b
--- /dev/null
+++ b/cpp/src/test/font_parsing_test.cc
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+
+#include "sfntly/data/font_input_stream.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/core/font_header_table.h"
+#include "sfntly/table/table.h"
+#include "sfntly/table/generic_table_builder.h"
+#include "sfntly/table/table_based_table_builder.h"
+#include "sfntly/tag.h"
+#include "sfntly/port/file_input_stream.h"
+#include "test/test_data.h"
+#include "test/test_font_utils.h"
+
+namespace sfntly {
+
+bool TestFontParsing() {
+  ByteVector input_buffer;
+  LoadFile(SAMPLE_TTF_FILE, &input_buffer);
+
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  // File based
+  FontBuilderArray font_builder_array;
+  BuilderForFontFile(SAMPLE_TTF_FILE, factory, &font_builder_array);
+  FontBuilderPtr font_builder = font_builder_array[0];
+  // Memory based
+  FontBuilderArray font_builder_array2;
+  factory->LoadFontsForBuilding(&input_buffer, &font_builder_array2);
+  FontBuilderPtr font_builder2 = font_builder_array2[0];
+
+  for (size_t i = 0; i < SAMPLE_TTF_KNOWN_TAGS; ++i) {
+    EXPECT_TRUE(font_builder->HasTableBuilder(TTF_KNOWN_TAGS[i]));
+    EXPECT_TRUE(font_builder2->HasTableBuilder(TTF_KNOWN_TAGS[i]));
+  }
+
+  // Generic table
+  Ptr<GenericTableBuilder> gdef_builder =
+      down_cast<GenericTableBuilder*>(font_builder->GetTableBuilder(Tag::feat));
+  HeaderPtr gdef_header = gdef_builder->header();
+  EXPECT_EQ(gdef_header->length(), TTF_LENGTH[SAMPLE_TTF_FEAT]);
+  EXPECT_EQ(gdef_header->offset(), TTF_OFFSET[SAMPLE_TTF_FEAT]);
+  EXPECT_EQ(gdef_header->checksum(), TTF_CHECKSUM[SAMPLE_TTF_FEAT]);
+  EXPECT_TRUE(gdef_header->checksum_valid());
+
+  WritableFontDataPtr wfd;
+  wfd.Attach(gdef_builder->Data());
+  ByteVector b;
+  b.resize(TTF_LENGTH[SAMPLE_TTF_FEAT]);
+  wfd->ReadBytes(0, &(b[0]), 0, TTF_LENGTH[SAMPLE_TTF_FEAT]);
+  EXPECT_EQ(memcmp(&(b[0]), TTF_FEAT_DATA, TTF_LENGTH[SAMPLE_TTF_FEAT]), 0);
+
+  // Header table
+  FontHeaderTableBuilderPtr header_builder =
+      down_cast<FontHeaderTable::Builder*>(
+          font_builder->GetTableBuilder(Tag::head));
+  HeaderPtr header_header = header_builder->header();
+  EXPECT_EQ(header_header->length(), TTF_LENGTH[SAMPLE_TTF_HEAD]);
+  EXPECT_EQ(header_header->offset(), TTF_OFFSET[SAMPLE_TTF_HEAD]);
+  EXPECT_EQ(header_header->checksum(), TTF_CHECKSUM[SAMPLE_TTF_HEAD]);
+  EXPECT_TRUE(header_header->checksum_valid());
+
+  // Data conformance
+  for (size_t i = 0; i < SAMPLE_TTF_KNOWN_TAGS; ++i) {
+    ByteVector b1, b2;
+    b1.resize(TTF_LENGTH[i]);
+    b2.resize(TTF_LENGTH[i]);
+    TableBuilderPtr builder1 =
+        font_builder->GetTableBuilder(TTF_KNOWN_TAGS[i]);
+    TableBuilderPtr builder2 =
+        font_builder2->GetTableBuilder(TTF_KNOWN_TAGS[i]);
+    WritableFontDataPtr wfd1;
+    wfd1.Attach(builder1->Data());
+    WritableFontDataPtr wfd2;
+    wfd2.Attach(builder2->Data());
+    wfd1->ReadBytes(0, &(b1[0]), 0, TTF_LENGTH[i]);
+    wfd2->ReadBytes(0, &(b2[0]), 0, TTF_LENGTH[i]);
+    EXPECT_EQ(memcmp(&(b1[0]), &(b2[0]), TTF_LENGTH[i]), 0);
+  }
+
+  return true;
+}
+
+bool TestTTFReadWrite() {
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  FontBuilderArray font_builder_array;
+  BuilderForFontFile(SAMPLE_TTF_FILE, factory, &font_builder_array);
+  FontBuilderPtr font_builder = font_builder_array[0];
+  FontPtr font;
+  font.Attach(font_builder->Build());
+  MemoryOutputStream output_stream;
+  factory->SerializeFont(font, &output_stream);
+  EXPECT_GE(output_stream.Size(), SAMPLE_TTF_SIZE);
+
+  return true;
+}
+
+bool TestTTFMemoryBasedReadWrite() {
+  ByteVector input_buffer;
+  LoadFile(SAMPLE_TTF_FILE, &input_buffer);
+
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  FontBuilderArray font_builder_array;
+  factory->LoadFontsForBuilding(&input_buffer, &font_builder_array);
+  FontBuilderPtr font_builder = font_builder_array[0];
+  FontPtr font;
+  font.Attach(font_builder->Build());
+  MemoryOutputStream output_stream;
+  factory->SerializeFont(font, &output_stream);
+  EXPECT_GE(output_stream.Size(), input_buffer.size());
+
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(FontParsing, All) {
+  ASSERT_TRUE(sfntly::TestFontParsing());
+  ASSERT_TRUE(sfntly::TestTTFReadWrite());
+  ASSERT_TRUE(sfntly::TestTTFMemoryBasedReadWrite());
+}
diff --git a/cpp/src/test/hdmx_test.cc b/cpp/src/test/hdmx_test.cc
new file mode 100644
index 0000000..cdc4ed0
--- /dev/null
+++ b/cpp/src/test/hdmx_test.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/table/core/horizontal_device_metrics_table.h"
+#include "test/test_data.h"
+#include "test/test_font_utils.h"
+
+namespace sfntly {
+
+const int32_t HDMX_VERSION = 0;
+const int32_t HDMX_NUM_RECORDS = 4;
+const int32_t HDMX_RECORD_SIZE = 628;
+const int32_t HDMX_PIXEL_SIZE[] = {10, 11, 12, 13};
+const int32_t HDMX_MAX_WIDTH[] = {5, 6, 7, 7};
+
+bool TestReadingHdmxTable() {
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  FontArray font_array;
+  LoadFont(SAMPLE_BITMAP_FONT, factory, &font_array);
+  FontPtr font = font_array[0];
+
+  HorizontalDeviceMetricsTablePtr hdmx_table =
+      down_cast<HorizontalDeviceMetricsTable*>(font->GetTable(Tag::hdmx));
+
+  EXPECT_FALSE(hdmx_table == NULL);
+
+  EXPECT_EQ(hdmx_table->Version(), HDMX_VERSION);
+  EXPECT_EQ(hdmx_table->NumRecords(), HDMX_NUM_RECORDS);
+  EXPECT_EQ(hdmx_table->RecordSize(), HDMX_RECORD_SIZE);
+
+  for (int32_t i = 0; i < HDMX_NUM_RECORDS; ++i) {
+    EXPECT_EQ(hdmx_table->PixelSize(i), HDMX_PIXEL_SIZE[i]);
+    EXPECT_EQ(hdmx_table->MaxWidth(i), HDMX_MAX_WIDTH[i]);
+  }
+
+  EXPECT_EQ(hdmx_table->Width(0, 0), HDMX_MAX_WIDTH[0]);
+  EXPECT_EQ(hdmx_table->Width(0, 19), HDMX_MAX_WIDTH[0]);
+  EXPECT_EQ(hdmx_table->Width(0, 623), HDMX_MAX_WIDTH[0]);
+  EXPECT_EQ(hdmx_table->Width(1, 0), HDMX_MAX_WIDTH[1]);
+  EXPECT_EQ(hdmx_table->Width(1, 19), HDMX_MAX_WIDTH[1]);
+  EXPECT_EQ(hdmx_table->Width(1, 623), HDMX_MAX_WIDTH[1]);
+  EXPECT_EQ(hdmx_table->Width(2, 0), HDMX_MAX_WIDTH[2]);
+  EXPECT_EQ(hdmx_table->Width(2, 19), HDMX_MAX_WIDTH[2]);
+  EXPECT_EQ(hdmx_table->Width(2, 623), HDMX_MAX_WIDTH[2]);
+  EXPECT_EQ(hdmx_table->Width(3, 0), HDMX_MAX_WIDTH[3]);
+  EXPECT_EQ(hdmx_table->Width(3, 19), HDMX_MAX_WIDTH[3]);
+  EXPECT_EQ(hdmx_table->Width(3, 623), HDMX_MAX_WIDTH[3]);
+
+#if defined(SFNTLY_NO_EXCEPTION)
+  EXPECT_EQ(hdmx_table->PixelSize(4), -1);
+  EXPECT_EQ(hdmx_table->PixelSize(-1), -1);
+  EXPECT_EQ(hdmx_table->MaxWidth(4), -1);
+  EXPECT_EQ(hdmx_table->MaxWidth(-1), -1);
+  EXPECT_EQ(hdmx_table->Width(0, 624), -1);
+  EXPECT_EQ(hdmx_table->Width(1, -1), -1);
+  EXPECT_EQ(hdmx_table->Width(-1, 0), -1);
+  EXPECT_EQ(hdmx_table->Width(-1, -1), -1);
+#endif
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(HdmxTable, All) {
+  ASSERT_TRUE(sfntly::TestReadingHdmxTable());
+}
diff --git a/cpp/src/test/lock_test.cc b/cpp/src/test/lock_test.cc
new file mode 100644
index 0000000..b29a4bf
--- /dev/null
+++ b/cpp/src/test/lock_test.cc
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include "gtest/gtest.h"
+#include "sfntly/port/lock.h"
+#include "test/platform_thread.h"
+
+namespace sfntly {
+
+// Basic test to make sure that Acquire()/Unlock()/Try() don't crash
+
+class BasicLockTestThread : public PlatformThread::Delegate {
+ public:
+  BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
+
+  virtual void ThreadMain() {
+    for (int i = 0; i < 10; i++) {
+      lock_->Acquire();
+      acquired_++;
+      lock_->Unlock();
+    }
+    for (int i = 0; i < 10; i++) {
+      lock_->Acquire();
+      acquired_++;
+      PlatformThread::Sleep(rand() % 20);
+      lock_->Unlock();
+    }
+    for (int i = 0; i < 10; i++) {
+      if (lock_->Try()) {
+        acquired_++;
+        PlatformThread::Sleep(rand() % 20);
+        lock_->Unlock();
+      }
+    }
+  }
+
+  int acquired() const { return acquired_; }
+
+ private:
+  Lock* lock_;
+  int acquired_;
+
+  NO_COPY_AND_ASSIGN(BasicLockTestThread);
+};
+
+bool BasicLockTest() {
+  Lock lock;
+  BasicLockTestThread thread(&lock);
+  PlatformThreadHandle handle = kNullThreadHandle;
+
+  EXPECT_TRUE(PlatformThread::Create(&thread, &handle));
+
+  int acquired = 0;
+  for (int i = 0; i < 5; i++) {
+    lock.Acquire();
+    acquired++;
+    lock.Unlock();
+  }
+  for (int i = 0; i < 10; i++) {
+    lock.Acquire();
+    acquired++;
+    PlatformThread::Sleep(rand() % 20);
+    lock.Unlock();
+  }
+  for (int i = 0; i < 10; i++) {
+    if (lock.Try()) {
+      acquired++;
+      PlatformThread::Sleep(rand() % 20);
+      lock.Unlock();
+    }
+  }
+  for (int i = 0; i < 5; i++) {
+    lock.Acquire();
+    acquired++;
+    PlatformThread::Sleep(rand() % 20);
+    lock.Unlock();
+  }
+
+  PlatformThread::Join(handle);
+
+  EXPECT_GE(acquired, 20);
+  EXPECT_GE(thread.acquired(), 20);
+
+  return true;
+}
+
+// Test that Try() works as expected -------------------------------------------
+
+class TryLockTestThread : public PlatformThread::Delegate {
+ public:
+  TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
+
+  virtual void ThreadMain() {
+    got_lock_ = lock_->Try();
+    if (got_lock_)
+      lock_->Unlock();
+  }
+
+  bool got_lock() const { return got_lock_; }
+
+ private:
+  Lock* lock_;
+  bool got_lock_;
+
+  NO_COPY_AND_ASSIGN(TryLockTestThread);
+};
+
+bool TryLockTest() {
+  Lock lock;
+
+  EXPECT_TRUE(lock.Try());
+  // We now have the lock....
+
+  // This thread will not be able to get the lock.
+  {
+    TryLockTestThread thread(&lock);
+    PlatformThreadHandle handle = kNullThreadHandle;
+
+    EXPECT_TRUE(PlatformThread::Create(&thread, &handle));
+
+    PlatformThread::Join(handle);
+
+    EXPECT_FALSE(thread.got_lock());
+  }
+
+  lock.Unlock();
+
+  // This thread will....
+  {
+    TryLockTestThread thread(&lock);
+    PlatformThreadHandle handle = kNullThreadHandle;
+
+    EXPECT_TRUE(PlatformThread::Create(&thread, &handle));
+
+    PlatformThread::Join(handle);
+
+    EXPECT_TRUE(thread.got_lock());
+    // But it released it....
+    EXPECT_TRUE(lock.Try());
+  }
+
+  lock.Unlock();
+  return true;
+}
+
+// Tests that locks actually exclude -------------------------------------------
+
+class MutexLockTestThread : public PlatformThread::Delegate {
+ public:
+  MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
+
+  // Static helper which can also be called from the main thread.
+  static void DoStuff(Lock* lock, int* value) {
+    for (int i = 0; i < 40; i++) {
+      lock->Acquire();
+      int v = *value;
+      PlatformThread::Sleep(rand() % 10);
+      *value = v + 1;
+      lock->Unlock();
+    }
+  }
+
+  virtual void ThreadMain() {
+    DoStuff(lock_, value_);
+  }
+
+ private:
+  Lock* lock_;
+  int* value_;
+
+  NO_COPY_AND_ASSIGN(MutexLockTestThread);
+};
+
+bool MutexTwoThreads() {
+  Lock lock;
+  int value = 0;
+
+  MutexLockTestThread thread(&lock, &value);
+  PlatformThreadHandle handle = kNullThreadHandle;
+
+  EXPECT_TRUE(PlatformThread::Create(&thread, &handle));
+
+  MutexLockTestThread::DoStuff(&lock, &value);
+
+  PlatformThread::Join(handle);
+
+  EXPECT_EQ(2 * 40, value);
+  return true;
+}
+
+bool MutexFourThreads() {
+  Lock lock;
+  int value = 0;
+
+  MutexLockTestThread thread1(&lock, &value);
+  MutexLockTestThread thread2(&lock, &value);
+  MutexLockTestThread thread3(&lock, &value);
+  PlatformThreadHandle handle1 = kNullThreadHandle;
+  PlatformThreadHandle handle2 = kNullThreadHandle;
+  PlatformThreadHandle handle3 = kNullThreadHandle;
+
+  EXPECT_TRUE(PlatformThread::Create(&thread1, &handle1));
+  EXPECT_TRUE(PlatformThread::Create(&thread2, &handle2));
+  EXPECT_TRUE(PlatformThread::Create(&thread3, &handle3));
+
+  MutexLockTestThread::DoStuff(&lock, &value);
+
+  PlatformThread::Join(handle1);
+  PlatformThread::Join(handle2);
+  PlatformThread::Join(handle3);
+
+  EXPECT_EQ(4 * 40, value);
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(LockTest, Basic) {
+  ASSERT_TRUE(sfntly::BasicLockTest());
+}
+
+TEST(LockTest, TryLock) {
+  ASSERT_TRUE(sfntly::TryLockTest());
+}
+
+TEST(LockTest, Mutex) {
+  ASSERT_TRUE(sfntly::MutexTwoThreads());
+  ASSERT_TRUE(sfntly::MutexFourThreads());
+}
diff --git a/cpp/src/test/memory_io_test.cc b/cpp/src/test/memory_io_test.cc
new file mode 100755
index 0000000..b34e1e7
--- /dev/null
+++ b/cpp/src/test/memory_io_test.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include <algorithm>
+
+#include "gtest/gtest.h"
+#include "sfntly/port/memory_input_stream.h"
+#include "sfntly/port/memory_output_stream.h"
+#include "sfntly/port/type.h"
+
+namespace {
+  const char* kTestData =
+"01234567890123456789012345678901234567890123456789"  // 50
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx"  // 100
+"yz";                                                 // 102
+  const size_t kTestBufferLen = 102;
+}
+
+namespace sfntly {
+
+bool TestMemoryInputStream() {
+  ByteVector test_buffer;
+  test_buffer.resize(kTestBufferLen);
+  std::copy(kTestData, kTestData + kTestBufferLen, test_buffer.begin());
+
+  MemoryInputStream is;
+  is.Attach(&(test_buffer[0]), kTestBufferLen);
+  EXPECT_EQ(is.Available(), (int32_t)kTestBufferLen);
+
+  // Read one byte
+  EXPECT_EQ(is.Read(), '0');  // position 1
+  EXPECT_EQ(is.Read(), '1');  // position 2
+  EXPECT_EQ(is.Read(), '2');  // position 3
+
+  // Read byte vector
+  ByteVector b;
+  b.resize(7);
+  EXPECT_EQ(is.Read(&b), 7);  // position 10
+  EXPECT_EQ(memcmp(&(b[0]), &(test_buffer[0]) + 3, 7), 0);
+
+  b.resize(17);
+  EXPECT_EQ(is.Read(&b, 7, 10), 10);  // position 20
+  EXPECT_EQ(memcmp(&(b[0]), &(test_buffer[0]) + 3, 17), 0);
+
+  // Test skip
+  b.clear();
+  b.resize(10);
+  EXPECT_EQ(is.Skip(30), 30);  // position 50
+  EXPECT_EQ(is.Read(&b), 10);  // position 60
+  EXPECT_EQ(memcmp(&(b[0]), &(test_buffer[0]) + 50, 10), 0);
+  b.clear();
+  b.resize(10);
+  EXPECT_EQ(is.Skip(-20), -20);  // position 40
+  EXPECT_EQ(is.Read(&b), 10);  // position 50
+  EXPECT_EQ(memcmp(&(b[0]), &(test_buffer[0]) + 40, 10), 0);
+
+  EXPECT_EQ(is.Available(), (int32_t)kTestBufferLen - 50);
+  EXPECT_EQ(is.Skip(-60), -50);  // Out of bound, position 0
+  EXPECT_EQ(is.Skip(kTestBufferLen + 10), (int32_t)kTestBufferLen);
+
+  b.clear();
+  b.resize(10);
+  is.Unread(&b);
+  EXPECT_EQ(memcmp(&(b[0]), &(test_buffer[0]) + kTestBufferLen - 10, 10), 0);
+
+  return true;
+}
+
+bool TestMemoryOutputStream() {
+  ByteVector test_buffer;
+  test_buffer.resize(kTestBufferLen);
+  std::copy(kTestData, kTestData + kTestBufferLen, test_buffer.begin());
+
+  MemoryOutputStream os;
+  os.Write(&(test_buffer[0]), (int32_t)50, (int32_t)(kTestBufferLen - 50));
+  EXPECT_EQ(os.Size(), kTestBufferLen - 50);
+  EXPECT_EQ(memcmp(os.Get(), &(test_buffer[0]) + 50, kTestBufferLen - 50), 0);
+
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(MemoryIO, All) {
+  ASSERT_TRUE(sfntly::TestMemoryInputStream());
+  ASSERT_TRUE(sfntly::TestMemoryOutputStream());
+}
diff --git a/cpp/src/test/name_editing_test.cc b/cpp/src/test/name_editing_test.cc
new file mode 100644
index 0000000..260d9d4
--- /dev/null
+++ b/cpp/src/test/name_editing_test.cc
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Must include this before ICU to avoid stdint redefinition issue.
+#include "sfntly/port/type.h"
+
+#include <unicode/ustring.h>
+#include <unicode/unistr.h>
+
+#include "gtest/gtest.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/port/memory_input_stream.h"
+#include "sfntly/port/memory_output_stream.h"
+#include "sfntly/table/core/name_table.h"
+#include "sfntly/tag.h"
+#include "test/test_data.h"
+#include "test/test_font_utils.h"
+
+namespace sfntly {
+
+static ByteVector input_buffer;
+
+void LoadTestFile(FontFactory* factory, FontBuilderArray* font_builders) {
+  assert(factory);
+  assert(font_builders);
+  if (input_buffer.empty()) {
+    LoadFile(SAMPLE_TTF_FILE, &input_buffer);
+  }
+  factory->LoadFontsForBuilding(&input_buffer, font_builders);
+}
+
+bool TestChangeOneName() {
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  FontBuilderArray font_builder_array;
+  LoadTestFile(factory, &font_builder_array);
+  FontBuilderPtr font_builder = font_builder_array[0];
+
+  NameTableBuilderPtr name_builder = down_cast<NameTable::Builder*>(
+      font_builder->GetTableBuilder(Tag::name));
+
+  // Change the font name.
+  NameEntryBuilderPtr neb =
+      name_builder->NameBuilder(PlatformId::kWindows,
+                                WindowsEncodingId::kUnicodeUCS2,
+                                WindowsLanguageId::kEnglish_UnitedStates,
+                                NameId::kFontFamilyName);
+  U_STRING_DECL(new_name, "Timothy", 7);
+  neb->SetName(new_name);
+
+  // Build the font.
+  FontPtr font;
+  font.Attach(font_builder->Build());
+
+  // Serialize and reload the serialized font.
+  MemoryOutputStream os;
+  factory->SerializeFont(font, &os);
+  MemoryInputStream is;
+  is.Attach(os.Get(), os.Size());
+  FontArray font_array;
+  factory->LoadFonts(&is, &font_array);
+  FontPtr new_font = font_array[0];
+
+  // Check the font name.
+  NameTablePtr name_table = down_cast<NameTable*>(font->GetTable(Tag::name));
+  UChar* name = name_table->Name(PlatformId::kWindows,
+                                 WindowsEncodingId::kUnicodeUCS2,
+                                 WindowsLanguageId::kEnglish_UnitedStates,
+                                 NameId::kFontFamilyName);
+  EXPECT_TRUE(name != NULL);
+  EXPECT_EQ(u_strcmp(name, new_name), 0);
+  delete[] name;
+  return true;
+}
+
+bool TestModifyNameTableAndRevert() {
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  FontBuilderArray font_builder_array;
+  LoadTestFile(factory, &font_builder_array);
+  FontBuilderPtr font_builder = font_builder_array[0];
+
+  NameTableBuilderPtr name_builder = down_cast<NameTable::Builder*>(
+      font_builder->GetTableBuilder(Tag::name));
+
+  // Change the font name.
+  NameEntryBuilderPtr neb =
+      name_builder->NameBuilder(PlatformId::kWindows,
+                                WindowsEncodingId::kUnicodeUCS2,
+                                WindowsLanguageId::kEnglish_UnitedStates,
+                                NameId::kFontFamilyName);
+  NameTable::NameEntry* neb_entry = neb->name_entry();
+  UChar* original_name = neb_entry->Name();
+  EXPECT_TRUE(original_name != NULL);
+
+  U_STRING_DECL(new_name, "Timothy", 7);
+  neb->SetName(new_name);
+  name_builder->RevertNames();
+
+  // Build the font.
+  FontPtr font;
+  font.Attach(font_builder->Build());
+
+  // Serialize and reload the serialized font.
+  MemoryOutputStream os;
+  factory->SerializeFont(font, &os);
+  MemoryInputStream is;
+  is.Attach(os.Get(), os.Size());
+  FontArray font_array;
+  factory->LoadFonts(&is, &font_array);
+  FontPtr new_font = font_array[0];
+
+  // Check the font name.
+  NameTablePtr name_table = down_cast<NameTable*>(font->GetTable(Tag::name));
+  UChar* name = name_table->Name(PlatformId::kWindows,
+                                 WindowsEncodingId::kUnicodeUCS2,
+                                 WindowsLanguageId::kEnglish_UnitedStates,
+                                 NameId::kFontFamilyName);
+
+  EXPECT_EQ(u_strcmp(name, original_name), 0);
+  delete[] name;
+  delete[] original_name;
+
+  return true;
+}
+
+bool TestRemoveOneName() {
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  FontBuilderArray font_builder_array;
+  LoadTestFile(factory, &font_builder_array);
+  FontBuilderPtr font_builder = font_builder_array[0];
+
+  NameTableBuilderPtr name_builder = down_cast<NameTable::Builder*>(
+      font_builder->GetTableBuilder(Tag::name));
+
+  EXPECT_TRUE(name_builder->Has(PlatformId::kWindows,
+                                WindowsEncodingId::kUnicodeUCS2,
+                                WindowsLanguageId::kEnglish_UnitedStates,
+                                NameId::kFontFamilyName));
+  EXPECT_TRUE(name_builder->Remove(PlatformId::kWindows,
+                                   WindowsEncodingId::kUnicodeUCS2,
+                                   WindowsLanguageId::kEnglish_UnitedStates,
+                                   NameId::kFontFamilyName));
+
+  // Build the font.
+  FontPtr font;
+  font.Attach(font_builder->Build());
+
+  // Serialize and reload the serialized font.
+  MemoryOutputStream os;
+  factory->SerializeFont(font, &os);
+  MemoryInputStream is;
+  is.Attach(os.Get(), os.Size());
+  FontArray font_array;
+  factory->LoadFonts(&is, &font_array);
+  FontPtr new_font = font_array[0];
+
+  // Check the font name.
+  NameTablePtr name_table = down_cast<NameTable*>(font->GetTable(Tag::name));
+  UChar* name = name_table->Name(PlatformId::kWindows,
+                                 WindowsEncodingId::kUnicodeUCS2,
+                                 WindowsLanguageId::kEnglish_UnitedStates,
+                                 NameId::kFontFamilyName);
+  EXPECT_TRUE(name == NULL);
+
+  return true;
+}
+
+// Note: Function is not implemented but the test case is built.  Uncomment
+//       when NameTable::clear() is implemented.
+/*
+bool TestClearAllNamesAndSetOne() {
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  FontBuilderArray font_builder_array;
+  LoadTestFile(factory, &font_builder_array);
+  FontBuilderPtr font_builder = font_builder_array[0];
+
+  NameTableBuilderPtr name_builder = down_cast<NameTable::Builder*>(
+      font_builder->GetTableBuilder(Tag::name));
+
+  EXPECT_GT(name_builder->builderCount(), 0);
+  name_builder->clear();
+  EXPECT_EQ(name_builder->builderCount(), 0);
+
+  // Change the font name.
+  NameEntryBuilderPtr neb =
+      name_builder->NameBuilder(PlatformId::kWindows,
+                                WindowsEncodingId::kUnicodeUCS2,
+                                WindowsLanguageId::kEnglish_UnitedStates,
+                                NameId::kFontFamilyName);
+  U_STRING_DECL(new_name, "Fred", 4);
+  neb->SetName(new_name);
+
+  // Build the font.
+  FontPtr font = font_builder->Build();
+
+  // Serialize and reload the serialized font.
+  MemoryOutputStream os;
+  factory->SerializeFont(font, &os);
+  FontArray font_array;
+  ByteArrayPtr new_ba = new MemoryByteArray(os.Get(), os.Size());
+  factory->LoadFonts(new_ba, &font_array);
+  FontPtr new_font = font_array[0];
+
+  // Check the font name.
+  NameTablePtr name_table = down_cast<NameTable*>(font->table(Tag::name));
+  UChar* name = name_table->Name(PlatformId::kWindows,
+                                 WindowsEncodingId::kUnicodeUCS2,
+                                 WindowsLanguageId::kEnglish_UnitedStates,
+                                 NameId::kFontFamilyName);
+  EXPECT_EQ(name_table->NameCount(), 1);
+  EXPECT_EQ(u_strcmp(name, new_name), 0);
+
+  delete[] name;
+  return true;
+}
+*/
+
+}  // namespace sfntly
+
+TEST(NameEditing, All) {
+  EXPECT_TRUE(sfntly::TestChangeOneName());
+  EXPECT_TRUE(sfntly::TestModifyNameTableAndRevert());
+  EXPECT_TRUE(sfntly::TestRemoveOneName());
+}
diff --git a/cpp/src/test/open_type_data_test.cc b/cpp/src/test/open_type_data_test.cc
new file mode 100644
index 0000000..0917aab
--- /dev/null
+++ b/cpp/src/test/open_type_data_test.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/data/writable_font_data.h"
+#include "sfntly/data/memory_byte_array.h"
+
+namespace sfntly {
+
+const byte_t TEST_OTF_DATA[] =
+    {0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
+
+bool TestOTFRead() {
+  ByteVector bytes;
+  for (size_t i = 0; i < sizeof(TEST_OTF_DATA) / sizeof(byte_t); ++i) {
+    bytes.push_back(TEST_OTF_DATA[i]);
+  }
+  ByteArrayPtr array = new MemoryByteArray(&(bytes[0]), bytes.size());
+  ReadableFontDataPtr data = new ReadableFontData(array);
+
+  EXPECT_EQ(-1, data->ReadByte(0));
+  EXPECT_EQ(0xff, data->ReadUByte(0));
+  EXPECT_EQ(0x01, data->ReadByte(1));
+  EXPECT_EQ(65281, data->ReadUShort(0));
+  EXPECT_EQ(-255, data->ReadShort(0));
+  EXPECT_EQ(16711937, data->ReadUInt24(0));
+  EXPECT_EQ(4278255873LL, data->ReadULong(0));
+  EXPECT_EQ(-16711423, data->ReadLong(0));
+  return true;
+}
+
+bool TestOTFCopy() {
+  ByteVector source_bytes(1024);
+  for (size_t i = 0; i < source_bytes.size(); ++i) {
+    source_bytes[i] = (byte_t)(i & 0xff);
+  }
+  ByteArrayPtr source_array = new MemoryByteArray(&(source_bytes[0]), 1024);
+  ReadableFontDataPtr source = new ReadableFontData(source_array);
+
+  ByteVector destination_bytes(1024);
+  ByteArrayPtr destination_array =
+      new MemoryByteArray(&(destination_bytes[0]), 1024);
+  WritableFontDataPtr destination = new WritableFontData(destination_array);
+
+  int32_t length = source->CopyTo(destination);
+  EXPECT_EQ(1024, length);
+  EXPECT_TRUE(std::equal(source_bytes.begin(), source_bytes.end(),
+                         destination_bytes.begin()));
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(OpenTypeData, All) {
+  ASSERT_TRUE(sfntly::TestOTFRead());
+  ASSERT_TRUE(sfntly::TestOTFCopy());
+}
diff --git a/cpp/src/test/otf_basic_editing_test.cc b/cpp/src/test/otf_basic_editing_test.cc
new file mode 100644
index 0000000..7388fac
--- /dev/null
+++ b/cpp/src/test/otf_basic_editing_test.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/table/core/font_header_table.h"
+#include "sfntly/tag.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/port/endian.h"
+#include "sfntly/port/file_input_stream.h"
+#include "sfntly/port/memory_output_stream.h"
+#include "test/test_data.h"
+#include "test/test_font_utils.h"
+
+namespace sfntly {
+
+bool TestOTFBasicEditing() {
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  FontBuilderArray font_builder_array;
+  BuilderForFontFile(SAMPLE_TTF_FILE, factory, &font_builder_array);
+  FontBuilderPtr font_builder = font_builder_array[0];
+
+  // ensure the builder is not bogus
+  EXPECT_TRUE(font_builder != NULL);
+  TableBuilderMap* builder_map = font_builder->table_builders();
+  EXPECT_TRUE(builder_map != NULL);
+  IntegerSet builder_tags;
+  for (TableBuilderMap::iterator i = builder_map->begin(),
+                                 e = builder_map->end(); i != e; ++i) {
+    EXPECT_TRUE(i->second != NULL);
+    if (i->second == NULL) {
+      char tag[5] = {0};
+      int32_t value = ToBE32(i->first);
+      memcpy(tag, &value, 4);
+      fprintf(stderr, "tag %s does not have valid builder\n", tag);
+    } else {
+      builder_tags.insert(i->first);
+    }
+  }
+
+  FontHeaderTableBuilderPtr header_builder =
+      down_cast<FontHeaderTable::Builder*>(
+          font_builder->GetTableBuilder(Tag::head));
+  int64_t mod_date = header_builder->Modified();
+  header_builder->SetModified(mod_date + 1);
+  FontPtr font;
+  font.Attach(font_builder->Build());
+
+  // ensure every table had a builder
+  const TableMap* table_map = font->GetTableMap();
+  for (TableMap::const_iterator i = table_map->begin(), e = table_map->end();
+                                i != e; ++i) {
+    TablePtr table = (*i).second;
+    HeaderPtr header = table->header();
+    EXPECT_TRUE(builder_tags.find(header->tag()) != builder_tags.end());
+    builder_tags.erase(header->tag());
+  }
+  EXPECT_TRUE(builder_tags.empty());
+
+  FontHeaderTablePtr header =
+      down_cast<FontHeaderTable*>(font->GetTable(Tag::head));
+  int64_t after_mod_date = header->Modified();
+  EXPECT_EQ(mod_date + 1, after_mod_date);
+
+  // Checksum correctness of builder.
+  TablePtr post = font->GetTable(Tag::post);
+  EXPECT_EQ(post->CalculatedChecksum(), TTF_CHECKSUM[SAMPLE_TTF_POST]);
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(OTFBasicEditing, All) {
+  ASSERT_TRUE(sfntly::TestOTFBasicEditing());
+}
diff --git a/cpp/src/test/platform_thread.cc b/cpp/src/test/platform_thread.cc
new file mode 100644
index 0000000..6a0b84b
--- /dev/null
+++ b/cpp/src/test/platform_thread.cc
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test/platform_thread.h"
+
+namespace sfntly {
+
+#if defined (WIN32)
+
+DWORD __stdcall ThreadFunc(void* params) {
+  PlatformThread::Delegate* delegate =
+      static_cast<PlatformThread::Delegate*>(params);
+  delegate->ThreadMain();
+  return 0;
+}
+
+// static
+bool PlatformThread::Create(Delegate* delegate,
+                            PlatformThreadHandle* thread_handle) {
+  assert(thread_handle);
+  *thread_handle = CreateThread(NULL, 0, ThreadFunc, delegate, 0, NULL);
+  if (!(*thread_handle)) {
+    return false;
+  }
+
+  return true;
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+  assert(thread_handle);
+  DWORD result = WaitForSingleObject(thread_handle, INFINITE);
+  assert(result == WAIT_OBJECT_0);
+  CloseHandle(thread_handle);
+}
+
+// static
+void PlatformThread::Sleep(int32_t duration_ms) {
+  ::Sleep(duration_ms);
+}
+
+#else
+
+void* ThreadFunc(void* params) {
+  PlatformThread::Delegate* delegate =
+      static_cast<PlatformThread::Delegate*>(params);
+  delegate->ThreadMain();
+  return NULL;
+}
+
+// static
+bool PlatformThread::Create(Delegate* delegate,
+                            PlatformThreadHandle* thread_handle) {
+  assert(thread_handle);
+
+  bool success = false;
+  pthread_attr_t attributes;
+  pthread_attr_init(&attributes);
+  success = !pthread_create(thread_handle, &attributes, ThreadFunc, delegate);
+  pthread_attr_destroy(&attributes);
+
+  return success;
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+  assert(thread_handle);
+  pthread_join(thread_handle, NULL);
+}
+
+// static
+void PlatformThread::Sleep(int32_t duration_ms) {
+  struct timespec sleep_time, remaining;
+
+  // Contains the portion of duration_ms >= 1 sec.
+  sleep_time.tv_sec = duration_ms / 1000;
+  duration_ms -= sleep_time.tv_sec * 1000;
+
+  // Contains the portion of duration_ms < 1 sec.
+  sleep_time.tv_nsec = duration_ms * 1000 * 1000;  // nanoseconds.
+
+  while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
+    sleep_time = remaining;
+}
+
+#endif  // WIN32
+
+}  // namespace sfntly
diff --git a/cpp/src/test/platform_thread.h b/cpp/src/test/platform_thread.h
new file mode 100644
index 0000000..f236f4c
--- /dev/null
+++ b/cpp/src/test/platform_thread.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Simple platform thread implementation used to test our cross-platform locks.
+// This is a trimmed down version of Chromium base/threading/platform_thread.h.
+
+#ifndef SFNTLY_CPP_SRC_TEST_PLATFORM_THREAD_H_
+#define SFNTLY_CPP_SRC_TEST_PLATFORM_THREAD_H_
+
+#if defined (WIN32)
+#include <windows.h>
+#else  // Assume pthread
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+#endif // if defined (WIN32)
+
+#include "sfntly/port/type.h"
+
+namespace sfntly {
+
+#if defined (WIN32)
+typedef HANDLE PlatformThreadHandle;
+const PlatformThreadHandle kNullThreadHandle = NULL;
+#else  // Assume pthread
+typedef pthread_t PlatformThreadHandle;
+const PlatformThreadHandle kNullThreadHandle = 0;
+#endif
+
+class PlatformThread {
+ public:
+  class Delegate {
+   public:
+     virtual ~Delegate() {}
+     virtual void ThreadMain() = 0;
+  };
+
+  // Sleeps for the specified duration (units are milliseconds).
+  static void Sleep(int32_t duration_ms);
+
+  // Creates a new thread using default stack size.  Upon success,
+  // |*thread_handle| will be assigned a handle to the newly created thread,
+  // and |delegate|'s ThreadMain method will be executed on the newly created
+  // thread.
+  // NOTE: When you are done with the thread handle, you must call Join to
+  // release system resources associated with the thread.  You must ensure that
+  // the Delegate object outlives the thread.
+  static bool Create(Delegate* delegate, PlatformThreadHandle* thread_handle);
+
+  // Joins with a thread created via the Create function.  This function blocks
+  // the caller until the designated thread exits.  This will invalidate
+  // |thread_handle|.
+  static void Join(PlatformThreadHandle thread_handle);
+
+private:
+  PlatformThread() {}
+  NO_COPY_AND_ASSIGN(PlatformThread);
+};
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_TEST_PLATFORM_THREAD_H_
diff --git a/cpp/src/test/serialization_test.cc b/cpp/src/test/serialization_test.cc
new file mode 100755
index 0000000..0f2f489
--- /dev/null
+++ b/cpp/src/test/serialization_test.cc
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/port/memory_input_stream.h"
+#include "sfntly/port/memory_output_stream.h"
+#include "test/test_data.h"
+#include "test/test_font_utils.h"
+#include "test/serialization_test.h"
+
+namespace sfntly {
+
+bool TestSerialization() {
+  FontFactoryPtr factory1, factory2, factory3;
+  factory1.Attach(FontFactory::GetInstance());
+  FontArray font_array;
+  LoadFont(SAMPLE_TTF_FILE, factory1, &font_array);
+  FontPtr original = font_array[0];
+
+  factory2.Attach(FontFactory::GetInstance());
+  FontBuilderArray font_builder_array;
+  BuilderForFontFile(SAMPLE_TTF_FILE, factory2, &font_builder_array);
+  FontBuilderPtr font_builder = font_builder_array[0];
+
+  FontPtr intermediate;
+  intermediate.Attach(font_builder->Build());
+  MemoryOutputStream os;
+  factory2->SerializeFont(intermediate, &os);
+
+  factory3.Attach(FontFactory::GetInstance());
+  FontArray new_font_array;
+  MemoryInputStream is;
+  is.Attach(os.Get(), os.Size());
+  factory3->LoadFonts(&is, &new_font_array);
+  FontPtr serialized = new_font_array[0];
+
+  // Check number of tables
+  EXPECT_EQ(original->num_tables(), serialized->num_tables());
+
+  // Check if same set of tables
+  const TableMap* original_tables = original->GetTableMap();
+  const TableMap* serialized_tables = serialized->GetTableMap();
+  EXPECT_EQ(original_tables->size(), serialized_tables->size());
+  TableMap::const_iterator not_found = serialized_tables->end();
+  for (TableMap::const_iterator b = original_tables->begin(),
+                                e = original_tables->end(); b != e; ++b) {
+    EXPECT_TRUE((serialized_tables->find(b->first) != not_found));
+  }
+
+  // TODO(arthurhsu): check cmap equivalence
+  // Check checksum equivalence
+  for (size_t i = 0; i < SAMPLE_TTF_KNOWN_TAGS; ++i) {
+      TablePtr original_table = original->GetTable(TTF_KNOWN_TAGS[i]);
+      TablePtr serialized_table = serialized->GetTable(TTF_KNOWN_TAGS[i]);
+    EXPECT_EQ(original_table->CalculatedChecksum(),
+              serialized_table->CalculatedChecksum());
+    EXPECT_EQ(original_table->DataLength(), serialized_table->DataLength());
+
+    if (TTF_KNOWN_TAGS[i] == Tag::hhea) {
+      EXPECT_TRUE(VerifyHHEA(original_table, serialized_table));
+    } else if (TTF_KNOWN_TAGS[i] == Tag::glyf) {
+        EXPECT_TRUE(VerifyGLYF(original_table, serialized_table));
+    } else if (TTF_KNOWN_TAGS[i] == Tag::hmtx) {
+        EXPECT_TRUE(VerifyHMTX(original_table, serialized_table));
+    } else if (TTF_KNOWN_TAGS[i] == Tag::loca) {
+        EXPECT_TRUE(VerifyLOCA(original_table, serialized_table));
+    } else if (TTF_KNOWN_TAGS[i] == Tag::maxp) {
+        EXPECT_TRUE(VerifyMAXP(original_table, serialized_table));
+    } else if (TTF_KNOWN_TAGS[i] == Tag::name) {
+        EXPECT_TRUE(VerifyNAME(original_table, serialized_table));
+    } else if (TTF_KNOWN_TAGS[i] == Tag::OS_2) {
+        EXPECT_TRUE(VerifyOS_2(original_table, serialized_table));
+    }
+  }
+
+  return true;
+}
+
+bool TestSerializationBitmap() {
+  FontFactoryPtr factory1, factory2, factory3;
+  factory1.Attach(FontFactory::GetInstance());
+  FontArray font_array;
+  LoadFont(SAMPLE_BITMAP_FONT, factory1, &font_array);
+  FontPtr original = font_array[0];
+
+  factory2.Attach(FontFactory::GetInstance());
+  FontBuilderArray font_builder_array;
+  BuilderForFontFile(SAMPLE_BITMAP_FONT, factory2, &font_builder_array);
+  FontBuilderPtr font_builder = font_builder_array[0];
+
+  FontPtr intermediate;
+  intermediate.Attach(font_builder->Build());
+  MemoryOutputStream os;
+  factory2->SerializeFont(intermediate, &os);
+
+  factory3.Attach(FontFactory::GetInstance());
+  FontArray new_font_array;
+  MemoryInputStream is;
+  is.Attach(os.Get(), os.Size());
+  factory3->LoadFonts(&is, &new_font_array);
+  FontPtr serialized = new_font_array[0];
+
+  // Check number of tables
+  EXPECT_EQ(original->num_tables(), serialized->num_tables());
+
+  // Check if same set of tables
+  const TableMap* original_tables = original->GetTableMap();
+  const TableMap* serialized_tables = serialized->GetTableMap();
+  EXPECT_EQ(original_tables->size(), serialized_tables->size());
+  TableMap::const_iterator not_found = serialized_tables->end();
+  for (TableMap::const_iterator b = original_tables->begin(),
+                                e = original_tables->end(); b != e; ++b) {
+    EXPECT_TRUE((serialized_tables->find(b->first) != not_found));
+  }
+
+  // Check checksum equivalence
+  for (size_t i = 0; i < SAMPLE_BITMAP_KNOWN_TAGS; ++i) {
+      TablePtr original_table = original->GetTable(BITMAP_KNOWN_TAGS[i]);
+      TablePtr serialized_table = serialized->GetTable(BITMAP_KNOWN_TAGS[i]);
+    EXPECT_EQ(original_table->CalculatedChecksum(),
+              serialized_table->CalculatedChecksum());
+    EXPECT_EQ(original_table->DataLength(), serialized_table->DataLength());
+  }
+
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(Serialization, Simple) {
+  ASSERT_TRUE(sfntly::TestSerialization());
+}
+
+TEST(Serialization, Bitmap) {
+  ASSERT_TRUE(sfntly::TestSerializationBitmap());
+}
diff --git a/cpp/src/test/serialization_test.h b/cpp/src/test/serialization_test.h
new file mode 100644
index 0000000..8996793
--- /dev/null
+++ b/cpp/src/test/serialization_test.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_TEST_SERIALIZATION_TEST_H_
+#define SFNTLY_CPP_SRC_TEST_SERIALIZATION_TEST_H_
+
+#include "sfntly/table/table.h"
+
+namespace sfntly {
+
+bool VerifyHHEA(Table* original, Table* target);
+bool VerifyGLYF(Table* original, Table* target);
+bool VerifyHMTX(Table* original, Table* target);
+bool VerifyLOCA(Table* original, Table* target);
+bool VerifyMAXP(Table* original, Table* target);
+bool VerifyNAME(Table* original, Table* target);
+bool VerifyOS_2(Table* original, Table* target);
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_TEST_SERIALIZATION_TEST_H_
diff --git a/cpp/src/test/smart_pointer_test.cc b/cpp/src/test/smart_pointer_test.cc
new file mode 100644
index 0000000..9e81baa
--- /dev/null
+++ b/cpp/src/test/smart_pointer_test.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#define ENABLE_OBJECT_COUNTER
+#include "sfntly/port/refcount.h"
+
+using sfntly::RefCounted;
+using sfntly::Ptr;
+
+class Foo : public RefCounted<Foo> {
+public:  // put in something to make sure it's not empty
+  int foo_;
+  int foo() { return foo_; }
+};
+
+bool TestSmartPointer() {
+  // scope out allocation
+  {
+    Ptr<Foo> p1;
+    p1 = new Foo();
+    EXPECT_EQ(size_t(1), p1->ref_count_);
+    EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_);
+
+    Ptr<Foo> p2;
+    p2 = p1;
+    EXPECT_EQ(size_t(2), p1->ref_count_);
+    EXPECT_EQ(size_t(2), p2->ref_count_);
+    EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_);
+
+    Ptr<Foo> p3;
+    p3 = p1;
+    EXPECT_EQ(size_t(3), p1->ref_count_);
+    EXPECT_EQ(size_t(3), p2->ref_count_);
+    EXPECT_EQ(size_t(3), p3->ref_count_);
+    EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_);
+
+    p2 = new Foo();
+    EXPECT_EQ(size_t(2), p1->ref_count_);
+    EXPECT_EQ(size_t(1), p2->ref_count_);
+    EXPECT_EQ(size_t(2), p3->ref_count_);
+    EXPECT_EQ(size_t(2), RefCounted<Foo>::object_counter_);
+
+    p3.Release();
+    EXPECT_EQ(size_t(1), p1->ref_count_);
+    EXPECT_EQ(NULL, p3.p_);
+    EXPECT_EQ(size_t(2), RefCounted<Foo>::object_counter_);
+
+    p2 = NULL;
+    EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_);
+
+    p1 = p1;
+    EXPECT_EQ(size_t(1), p1->ref_count_);
+    EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_);
+
+    p1 = &(*p1);
+    EXPECT_EQ(size_t(1), p1->ref_count_);
+    EXPECT_EQ(size_t(1), RefCounted<Foo>::object_counter_);
+  }
+  EXPECT_EQ(size_t(0), RefCounted<Foo>::object_counter_);
+  return true;
+}
+
+TEST(SmartPointer, All) {
+  ASSERT_TRUE(TestSmartPointer());
+}
diff --git a/cpp/src/test/test_data.cc b/cpp/src/test/test_data.cc
new file mode 100644
index 0000000..05bc759
--- /dev/null
+++ b/cpp/src/test/test_data.cc
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/tag.cc"
+#include "test/test_data.h"
+
+namespace sfntly {
+
+// If the TTF file used in test changed, the verify*.cc in test need to be
+// changed also.
+// TODO(arthurhsu): Refactor this into a test class and have all const inside.
+//                  This way we can test multiple fonts using same set of
+//                  code.
+
+const char* SAMPLE_TTF_FILE = "Tuffy.ttf";
+const char* SAMPLE_BITMAP_FONT = "AnonymousPro-Regular.ttf";
+
+const size_t SAMPLE_TTF_SIZE = 183936;
+const size_t SAMPLE_TTF_TABLES = 17;
+const size_t SAMPLE_TTF_KNOWN_TAGS = 16;
+const size_t SAMPLE_BITMAP_KNOWN_TAGS = 20;
+const size_t SAMPLE_TTF_FEAT = 3;
+const size_t SAMPLE_TTF_HEAD = 6;
+const size_t SAMPLE_TTF_POST = 14;
+
+const int32_t TTF_KNOWN_TAGS[] = {
+    Tag::OS_2, Tag::cmap, Tag::cvt,  Tag::feat, Tag::gasp,
+    Tag::glyf, Tag::head, Tag::hhea, Tag::hmtx, Tag::kern,
+    Tag::loca, Tag::maxp, Tag::morx, Tag::name, Tag::post,
+    Tag::prop };
+
+const int32_t BITMAP_KNOWN_TAGS[] = {
+    Tag::EBDT, Tag::EBLC, Tag::EBSC, Tag::LTSH, Tag::OS_2,
+    Tag::VDMX, Tag::cmap, Tag::cvt,  Tag::fpgm, Tag::gasp,
+    Tag::glyf, Tag::hdmx, Tag::head, Tag::hhea, Tag::hmtx,
+    Tag::loca, Tag::maxp, Tag::name, Tag::post, Tag::prep };
+
+const int64_t TTF_CHECKSUM[] = {
+    0xD463FC48, 0x252028D1, 0x0065078A, 0xC01407B5, 0xFFFF0003,
+    0x9544342B, 0xFC8F16AD, 0x0EC30C7A, 0xA029CD5D, 0x32513087,
+    0x05C323B0, 0x06320195, 0x3B67E701, 0xE7DB08F3, 0xD46E5E89,
+    0xE6EB4A27 };
+
+const int64_t TTF_OFFSET[] = {
+    0x00000198, 0x00001964, 0x000025B0, 0x0002CA74, 0x0002C854,
+    0x00003D34, 0x0000011C, 0x00000154, 0x000001F0, 0x000245D8,
+    0x000025B8, 0x00000178, 0x0002CAB4, 0x00024860, 0x00028854,
+    0x0002C85C };
+
+const int32_t TTF_LENGTH[] = {
+            86,       3146,          8,         64,          8,
+        133284,         54,         36,       6002,        648,
+          6012,         32,        944,      16371,      16383,
+           536 };
+
+const unsigned char TTF_FEAT_DATA[] = {
+    0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+    0, 0, 0, 0x30, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0x34,
+    0, 0, 1, 1, 0, 0xB, 0, 2, 0, 0, 0, 0x38, 0xC0, 0, 1, 2,
+    0, 0, 1, 3, 0, 2, 1, 4, 0, 0, 1, 5, 0, 2, 1, 6 };
+
+}  // namespace sfntly
diff --git a/cpp/src/test/test_data.h b/cpp/src/test/test_data.h
new file mode 100644
index 0000000..d5e576f
--- /dev/null
+++ b/cpp/src/test/test_data.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_TEST_TEST_DATA_H_
+#define SFNTLY_CPP_SRC_TEST_TEST_DATA_H_
+
+#include "sfntly/tag.h"
+
+namespace sfntly {
+
+extern const char* SAMPLE_TTF_FILE;
+extern const char* SAMPLE_BITMAP_FONT;
+
+extern const size_t SAMPLE_TTF_SIZE;
+extern const size_t SAMPLE_TTF_TABLES;
+extern const size_t SAMPLE_TTF_KNOWN_TAGS;
+extern const size_t SAMPLE_BITMAP_KNOWN_TAGS;
+extern const size_t SAMPLE_TTF_FEAT;
+extern const size_t SAMPLE_TTF_HEAD;
+extern const size_t SAMPLE_TTF_POST;
+
+extern const int32_t TTF_KNOWN_TAGS[];
+extern const int32_t BITMAP_KNOWN_TAGS[];
+extern const int64_t TTF_CHECKSUM[];
+extern const int64_t TTF_OFFSET[];
+extern const int32_t TTF_LENGTH[];
+extern const unsigned char TTF_FEAT_DATA[];
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_TEST_TEST_DATA_H_
diff --git a/cpp/src/test/test_font_utils.cc b/cpp/src/test/test_font_utils.cc
new file mode 100644
index 0000000..d59b52b
--- /dev/null
+++ b/cpp/src/test/test_font_utils.cc
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+#include "gtest/gtest.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/data/growable_memory_byte_array.h"
+#include "sfntly/port/file_input_stream.h"
+#include "test/test_font_utils.h"
+
+namespace sfntly {
+
+void BuilderForFontFile(const char* font_path, FontFactory* factory,
+                        FontBuilderArray* builders) {
+  assert(factory);
+  FileInputStream is;
+  is.Open(font_path);
+  factory->LoadFontsForBuilding(&is, builders);
+  EXPECT_GT(builders->size(), static_cast<size_t>(0));
+}
+
+void SerializeFont(const char* font_path, FontFactory* factory, Font* font) {
+  assert(font_path);
+  assert(factory);
+  assert(font);
+  MemoryOutputStream output_stream;
+  factory->SerializeFont(font, &output_stream);
+  SerializeToFile(&output_stream, font_path);
+}
+
+void LoadFont(const char* font_path, FontFactory* factory, FontArray* fonts) {
+  FileInputStream is;
+  is.Open(font_path);
+  factory->LoadFonts(&is, fonts);
+  is.Close();
+}
+
+void LoadFontUsingByteVector(const char* font_path,
+                            bool fingerprint,
+                            FontArray* fonts) {
+  ByteVector bv;
+  LoadFile(font_path, &bv);
+  FontFactoryPtr factory;
+  factory.Attach(FontFactory::GetInstance());
+  factory->FingerprintFont(fingerprint);
+  factory->LoadFonts(&bv, fonts);
+}
+
+void LoadFile(const char* input_file_path, ByteVector* input_buffer) {
+  assert(input_file_path);
+  assert(input_buffer);
+
+  FILE* input_file = NULL;
+#if defined WIN32
+  fopen_s(&input_file, input_file_path, "rb");
+#else
+  input_file = fopen(input_file_path, "rb");
+#endif
+  EXPECT_NE(input_file, reinterpret_cast<FILE*>(NULL));
+  fseek(input_file, 0, SEEK_END);
+  size_t file_size = ftell(input_file);
+  fseek(input_file, 0, SEEK_SET);
+  input_buffer->resize(file_size);
+  size_t bytes_read = fread(&((*input_buffer)[0]), 1, file_size, input_file);
+  EXPECT_EQ(bytes_read, file_size);
+  fclose(input_file);
+}
+
+void SerializeToFile(MemoryOutputStream* output_stream, const char* file_path) {
+  assert(file_path);
+  assert(output_stream);
+
+  FILE* output_file = NULL;
+#if defined WIN32
+  fopen_s(&output_file, file_path, "wb");
+#else
+  output_file = fopen(file_path, "wb");
+#endif
+  EXPECT_NE(output_file, reinterpret_cast<FILE*>(NULL));
+  fwrite(output_stream->Get(), 1, output_stream->Size(), output_file);
+  fflush(output_file);
+  fclose(output_file);
+}
+
+void HexDump(const unsigned char* byte_data, size_t length) {
+  if (byte_data == NULL || length == 0) {
+    fprintf(stderr, "<NULL>\n");
+    return;
+  }
+
+  fprintf(stderr, "data length = %ld (%lx)\n", length, length);
+  for (size_t i = 0; i < length; ++i) {
+    fprintf(stderr, "%02x ", byte_data[i]);
+    if ((i & 0xf) == 0xf) {
+      fprintf(stderr, "\n");
+    }
+  }
+  fprintf(stderr, "\n");
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/test/test_font_utils.h b/cpp/src/test/test_font_utils.h
new file mode 100644
index 0000000..57fde7a
--- /dev/null
+++ b/cpp/src/test/test_font_utils.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_TEST_TEST_FONT_UTILS_H_
+#define SFNTLY_CPP_SRC_TEST_TEST_FONT_UTILS_H_
+
+#include "sfntly/font.h"
+#include "sfntly/font_factory.h"
+#include "sfntly/port/memory_output_stream.h"
+
+namespace sfntly {
+
+void BuilderForFontFile(const char* font_path, FontFactory* factory,
+                        FontBuilderArray* builders);
+void SerializeFont(const char* font_path, FontFactory* factory, Font* font);
+void LoadFont(const char* font_path, FontFactory* factory, FontArray* fonts);
+void LoadFontUsingByteVector(const char* font_path,
+                            bool fingerprint,
+                            FontArray* fonts);
+
+void LoadFile(const char* input_file_path, ByteVector* input_buffer);
+void SerializeToFile(MemoryOutputStream* output_stream, const char* file_path);
+
+void HexDump(const unsigned char* byte_data, size_t length);
+
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_TEST_TEST_FONT_UTILS_H_
diff --git a/cpp/src/test/test_utils.cc b/cpp/src/test/test_utils.cc
new file mode 100644
index 0000000..4751b92
--- /dev/null
+++ b/cpp/src/test/test_utils.cc
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test/test_utils.h"
+
+#include <stdio.h>
+#include <unicode/ucnv.h>
+#include <unicode/uchar.h>
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/data/growable_memory_byte_array.h"
+#include "sfntly/port/file_input_stream.h"
+
+namespace sfntly {
+TestUtils::TestUtils() {}
+
+// static
+// OutputStream CreateOutputStream(const char *file_path) {
+// }
+
+// static
+// void TestUtils::CreateNewFile(const char* file_path) {
+// }
+
+// static
+int32_t TestUtils::EncodeOneChar(UConverter* encoder, int16_t uchar) {
+  char* target = new char[ucnv_getMaxCharSize(encoder) * 2];
+  char* target_end;
+  UChar* source = new UChar[2];
+  UChar* source_end;
+  source[0] = (UChar)uchar;
+  source[1] = 0;
+  UErrorCode status = U_ZERO_ERROR;
+  source_end = source;
+  target_end = target;
+  ucnv_fromUnicode(encoder, &target_end, target + 4,
+                   (const UChar**)&source_end, source + sizeof(UChar),
+                   NULL, TRUE, &status);
+  if (!U_SUCCESS(status)) {
+    fprintf(stderr, "Error occured in conversion of %d: %s\n",
+            uchar, u_errorName(status));
+    delete[] source;
+    delete[] target;
+    return 0;
+  }
+  int32_t enc_char = 0;
+  for (int32_t position = 0; position < target_end - target; ++position) {
+    enc_char <<= 8;
+    enc_char |= (target[position] & 0xff);
+  }
+  delete[] source;
+  delete[] target;
+  return enc_char;
+}
+
+// static
+UConverter* TestUtils::GetEncoder(const char* charset_name) {
+  if (charset_name == NULL || strcmp(charset_name, "") == 0)
+    return NULL;
+  UErrorCode status = U_ZERO_ERROR;
+  UConverter* conv = ucnv_open(charset_name, &status);
+  // if (!U_SUCCESS(status))
+  //   return NULL;
+  return conv;  // returns NULL @ error anyway
+}
+
+// Get a file's extension
+// static
+const char* TestUtils::Extension(const char* file_path) {
+  if (!file_path)
+    return NULL;
+  return strrchr(file_path, EXTENSION_SEPARATOR);
+}
+}
diff --git a/cpp/src/test/test_utils.h b/cpp/src/test/test_utils.h
new file mode 100644
index 0000000..af3ffd6
--- /dev/null
+++ b/cpp/src/test/test_utils.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SFNTLY_CPP_SRC_TEST_TEST_UTILS_H_
+#define SFNTLY_CPP_SRC_TEST_TEST_UTILS_H_
+
+// Must include this before ICU to avoid stdint redefinition issue.
+#include "sfntly/port/type.h"
+
+#include <unicode/ucnv.h>
+
+#include <string>
+
+#include "sfntly/font.h"
+#include "sfntly/data/memory_byte_array.h"
+
+namespace sfntly {
+class TestUtils {
+  TestUtils();
+
+ public:
+  // Compare sections of two byte arrays for equality
+  // @param b1 byte array 1
+  // @param offset1 offset for comparison in byte array 1
+  // @param b2 byte array 2
+  // @param offset2 offset for comparison in byte array 2
+  // @param length the length of the byte arrays to compare
+  // @return true if the array segments are equal; false otherwise
+  // TODO(dfilimon): implement
+  static bool Equals(ByteArray* b1,
+                     int32_t offset1,
+                     ByteArray* b2,
+                     int32_t offset2);
+
+  // @param offset1 offset to start comparing the first ByteArray from
+  // @param ba1 the first ByteArray
+  // @param offset2 offset to start comparing the second ByteArray from
+  // @param ba2 the second ByteArray
+  // @param length the number of bytes to compare
+  // @return true if all bytes in the ranges given are equal; false otherwise
+  // TODO(dfilimon): implement
+  static bool Equals(ByteArray* b1,
+                     int32_t offset1,
+                     ByteArray* b2,
+                     int32_t offset2,
+                     int32_t length);
+
+  // TODO(dfilimon): implement FileOutputStream in port/file_output_stream.*
+  // static OutputStream createOutputStream(const char* file_path);
+
+  // TODO(dfilimon): adapt & implement
+  // static FileChannel createFilechannelForWriting(File file);
+
+  // Creates a new file including deleting an already existing file with the
+  // same path and name and creating any needed directories.
+  // TODO(dfilimon): implement
+  static void CreateNewFile(const char* file_path);
+
+  // Converts an integer into a 4 character string using the ASCII encoding.
+  // @param i the value to convert
+  // @return the String based on the number
+  // TODO(dfilimon): implement
+  static void DumpLongAsString(int32_t i, std::string* result);
+
+  // Calculate an OpenType checksum from the array.
+  // @param b the array to calculate checksum on
+  // @param offset the starting index in the array
+  // @param length the number of bytes to check; must be a multiple of 4
+  // @return checksum
+  // TODO(dfilimon): implement
+  static int64_t CheckSum(ByteArray* b, int32_t offset, int32_t length);
+
+  // Encode a single character in UTF-16.
+  // We only support the BMP for now
+  // @param encoder the encoder to use for the encoding
+  // @param uchar the Unicode character to encode
+  // @return the encoded character
+  static int32_t EncodeOneChar(UConverter* encoder, int16_t uchar);
+
+  // Get an encoder for the charset name.
+  // If the name is null or the empty string then just return null.
+  // @param charsetName the charset to get an encoder for
+  // @return an encoder or null if no encoder available for charset name
+  static UConverter* GetEncoder(const char* charsetName);
+
+ private:
+  static const char EXTENSION_SEPARATOR = '.';
+
+ public:
+  // Get the extension of a file's name.
+  // @param file the whose name to process
+  // @return string containing the extension or an empty string if
+  // there is no extension
+  static const char* Extension(const char* file_path);
+};
+}
+#endif  // SFNTLY_CPP_SRC_TEST_TEST_UTILS_H_
diff --git a/cpp/src/test/test_utils_test.cc b/cpp/src/test/test_utils_test.cc
new file mode 100644
index 0000000..9afc03c
--- /dev/null
+++ b/cpp/src/test/test_utils_test.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Must include at the first line to avoid ICU / stdint conflict.
+#include "sfntly/port/type.h"
+
+#include <stdio.h>
+#include <unicode/ucnv.h>
+#include <unicode/uchar.h>
+
+#include "gtest/gtest.h"
+#include "test/test_utils.h"
+
+namespace sfntly {
+
+// Check if proper encoding is being performed
+// Conversion is done from UTF16 to UTF8, SJIS
+bool TestEncoding() {
+  UConverter* conv = TestUtils::GetEncoder("utf8");
+  EXPECT_TRUE(conv != NULL);
+  // Ūnĭcōde̽
+  UChar from[8] = {0x016A, 0x006E, 0x012D, 0x0063, 0x014D, 0x0064, 0x0065,
+                   0x033D};
+  int32_t want[12] = {0xc5, 0xaa, 0x6e, 0xc4, 0xad, 0x63, 0xc5, 0x8d, 0x64,
+                      0x65, 0xcc, 0xbd};
+  int32_t i, j = 0;
+  for (i = 0; i < 7; ++i) {
+    int32_t encoded = TestUtils::EncodeOneChar(conv, (int16_t)from[i]);
+    for (; encoded; encoded <<= 8) {
+      byte_t b = (encoded & 0xff000000) >> 24;
+      if (!b)
+        continue;
+      EXPECT_EQ(want[j], b);
+      if (want[j++] != b) {
+        ucnv_close(conv);
+        return false;
+      }
+    }
+  }
+  ucnv_close(conv);
+  return true;
+}
+
+// Check if the proper extension is obtained
+bool TestExtension() {
+  // usual file name
+  const char *result;
+  result = TestUtils::Extension("../data/ext/tuffy.ttf");
+  EXPECT_EQ(strcmp(result, ".ttf"), 0);
+
+  // more than one 'extension'
+  result = TestUtils::Extension("tuffy.ttf.fake");
+  EXPECT_EQ(strcmp(result, ".fake"), 0);
+
+  // no extension
+  result = TestUtils::Extension("tuffy");
+  EXPECT_STREQ(result, NULL);
+
+  // bogus extension
+  result = TestUtils::Extension("tuffy.");
+  EXPECT_EQ(strcmp(result, "."), 0);
+
+  return true;
+}
+
+}  // namespace sfntly
+
+TEST(TestUtils, All) {
+  ASSERT_TRUE(sfntly::TestExtension());
+  ASSERT_TRUE(sfntly::TestEncoding());
+}
diff --git a/cpp/src/test/test_xml_utils.cc b/cpp/src/test/test_xml_utils.cc
new file mode 100644
index 0000000..dc65add
--- /dev/null
+++ b/cpp/src/test/test_xml_utils.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <map>
+#include <string>
+#include "test/test_xml_utils.h"
+#include "test/tinyxml/tinyxml.h"
+
+namespace sfntly {
+void InternalGetNodesWithName(const TiXmlNode* node, const std::string& name,
+                              TiXmlNodeVector* wanted_nodes) {
+  if (node->ValueStr() == name)
+    wanted_nodes->push_back(node);
+  for (const TiXmlNode* child = node->FirstChild();
+       child != NULL; child = child->NextSibling()) {
+    InternalGetNodesWithName(child, name, wanted_nodes);
+  }
+}
+
+TiXmlNodeVector* GetNodesWithName(const TiXmlNode* node,
+                                  const std::string& name) {
+  TiXmlNodeVector* wanted_nodes = new TiXmlNodeVector;
+  InternalGetNodesWithName(node, name, wanted_nodes);
+  return wanted_nodes;
+}
+
+const TiXmlAttribute* GetAttribute(const TiXmlNode* node,
+                                   const std::string& name) {
+  for (const TiXmlAttribute* attribute = node->ToElement()->FirstAttribute();
+       attribute != NULL; attribute = attribute->Next()) {
+    if (attribute->Name() == name) {
+      return attribute;
+    }
+  }
+  return NULL;
+}
+}
diff --git a/cpp/src/test/test_xml_utils.h b/cpp/src/test/test_xml_utils.h
new file mode 100644
index 0000000..7a5fe49
--- /dev/null
+++ b/cpp/src/test/test_xml_utils.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/port/refcount.h"
+#include "test/tinyxml/tinyxml.h"
+
+#ifndef SFNTLY_CPP_SRC_TEST_TEST_XML_UTILS_H_
+#define SFNTLY_CPP_SRC_TEST_TEST_XML_UTILS_H_
+
+namespace sfntly {
+typedef std::map<std::string, std::string> AttributeMap;
+typedef std::vector<const TiXmlNode*> TiXmlNodeVector;
+
+TiXmlNodeVector* GetNodesWithName(const TiXmlNode* node,
+                                  const std::string& name);
+const TiXmlAttribute* GetAttribute(const TiXmlNode* node,
+                                   const std::string& name);
+}  // namespace sfntly
+
+#endif  // SFNTLY_CPP_SRC_TEST_TEST_XML_UTILS_H_
diff --git a/cpp/src/test/tinyxml/tinystr.cpp b/cpp/src/test/tinyxml/tinystr.cpp
new file mode 100644
index 0000000..0665768
--- /dev/null
+++ b/cpp/src/test/tinyxml/tinystr.cpp
@@ -0,0 +1,111 @@
+/*
+www.sourceforge.net/projects/tinyxml
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+
+#ifndef TIXML_USE_STL
+
+#include "tinystr.h"
+
+// Error value for find primitive
+const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1);
+
+
+// Null rep.
+TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } };
+
+
+void TiXmlString::reserve (size_type cap)
+{
+	if (cap > capacity())
+	{
+		TiXmlString tmp;
+		tmp.init(length(), cap);
+		memcpy(tmp.start(), data(), length());
+		swap(tmp);
+	}
+}
+
+
+TiXmlString& TiXmlString::assign(const char* str, size_type len)
+{
+	size_type cap = capacity();
+	if (len > cap || cap > 3*(len + 8))
+	{
+		TiXmlString tmp;
+		tmp.init(len);
+		memcpy(tmp.start(), str, len);
+		swap(tmp);
+	}
+	else
+	{
+		memmove(start(), str, len);
+		set_size(len);
+	}
+	return *this;
+}
+
+
+TiXmlString& TiXmlString::append(const char* str, size_type len)
+{
+	size_type newsize = length() + len;
+	if (newsize > capacity())
+	{
+		reserve (newsize + capacity());
+	}
+	memmove(finish(), str, len);
+	set_size(newsize);
+	return *this;
+}
+
+
+TiXmlString operator + (const TiXmlString & a, const TiXmlString & b)
+{
+	TiXmlString tmp;
+	tmp.reserve(a.length() + b.length());
+	tmp += a;
+	tmp += b;
+	return tmp;
+}
+
+TiXmlString operator + (const TiXmlString & a, const char* b)
+{
+	TiXmlString tmp;
+	TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );
+	tmp.reserve(a.length() + b_len);
+	tmp += a;
+	tmp.append(b, b_len);
+	return tmp;
+}
+
+TiXmlString operator + (const char* a, const TiXmlString & b)
+{
+	TiXmlString tmp;
+	TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );
+	tmp.reserve(a_len + b.length());
+	tmp.append(a, a_len);
+	tmp += b;
+	return tmp;
+}
+
+
+#endif	// TIXML_USE_STL
diff --git a/cpp/src/test/tinyxml/tinystr.h b/cpp/src/test/tinyxml/tinystr.h
new file mode 100644
index 0000000..89cca33
--- /dev/null
+++ b/cpp/src/test/tinyxml/tinystr.h
@@ -0,0 +1,305 @@
+/*
+www.sourceforge.net/projects/tinyxml
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+
+#ifndef TIXML_USE_STL
+
+#ifndef TIXML_STRING_INCLUDED
+#define TIXML_STRING_INCLUDED
+
+#include <assert.h>
+#include <string.h>
+
+/*	The support for explicit isn't that universal, and it isn't really
+	required - it is used to check that the TiXmlString class isn't incorrectly
+	used. Be nice to old compilers and macro it here:
+*/
+#if defined(_MSC_VER) && (_MSC_VER >= 1200 )
+	// Microsoft visual studio, version 6 and higher.
+	#define TIXML_EXPLICIT explicit
+#elif defined(__GNUC__) && (__GNUC__ >= 3 )
+	// GCC version 3 and higher.s
+	#define TIXML_EXPLICIT explicit
+#else
+	#define TIXML_EXPLICIT
+#endif
+
+
+/*
+   TiXmlString is an emulation of a subset of the std::string template.
+   Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.
+   Only the member functions relevant to the TinyXML project have been implemented.
+   The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase
+   a string and there's no more room, we allocate a buffer twice as big as we need.
+*/
+class TiXmlString
+{
+  public :
+	// The size type used
+  	typedef size_t size_type;
+
+	// Error value for find primitive
+	static const size_type npos; // = -1;
+
+
+	// TiXmlString empty constructor
+	TiXmlString () : rep_(&nullrep_)
+	{
+	}
+
+	// TiXmlString copy constructor
+	TiXmlString ( const TiXmlString & copy) : rep_(0)
+	{
+		init(copy.length());
+		memcpy(start(), copy.data(), length());
+	}
+
+	// TiXmlString constructor, based on a string
+	TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0)
+	{
+		init( static_cast<size_type>( strlen(copy) ));
+		memcpy(start(), copy, length());
+	}
+
+	// TiXmlString constructor, based on a string
+	TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0)
+	{
+		init(len);
+		memcpy(start(), str, len);
+	}
+
+	// TiXmlString destructor
+	~TiXmlString ()
+	{
+		quit();
+	}
+
+	TiXmlString& operator = (const char * copy)
+	{
+		return assign( copy, (size_type)strlen(copy));
+	}
+
+	TiXmlString& operator = (const TiXmlString & copy)
+	{
+		return assign(copy.start(), copy.length());
+	}
+
+
+	// += operator. Maps to append
+	TiXmlString& operator += (const char * suffix)
+	{
+		return append(suffix, static_cast<size_type>( strlen(suffix) ));
+	}
+
+	// += operator. Maps to append
+	TiXmlString& operator += (char single)
+	{
+		return append(&single, 1);
+	}
+
+	// += operator. Maps to append
+	TiXmlString& operator += (const TiXmlString & suffix)
+	{
+		return append(suffix.data(), suffix.length());
+	}
+
+
+	// Convert a TiXmlString into a null-terminated char *
+	const char * c_str () const { return rep_->str; }
+
+	// Convert a TiXmlString into a char * (need not be null terminated).
+	const char * data () const { return rep_->str; }
+
+	// Return the length of a TiXmlString
+	size_type length () const { return rep_->size; }
+
+	// Alias for length()
+	size_type size () const { return rep_->size; }
+
+	// Checks if a TiXmlString is empty
+	bool empty () const { return rep_->size == 0; }
+
+	// Return capacity of string
+	size_type capacity () const { return rep_->capacity; }
+
+
+	// single char extraction
+	const char& at (size_type index) const
+	{
+		assert( index < length() );
+		return rep_->str[ index ];
+	}
+
+	// [] operator
+	char& operator [] (size_type index) const
+	{
+		assert( index < length() );
+		return rep_->str[ index ];
+	}
+
+	// find a char in a string. Return TiXmlString::npos if not found
+	size_type find (char lookup) const
+	{
+		return find(lookup, 0);
+	}
+
+	// find a char in a string from an offset. Return TiXmlString::npos if not found
+	size_type find (char tofind, size_type offset) const
+	{
+		if (offset >= length()) return npos;
+
+		for (const char* p = c_str() + offset; *p != '\0'; ++p)
+		{
+		   if (*p == tofind) return static_cast< size_type >( p - c_str() );
+		}
+		return npos;
+	}
+
+	void clear ()
+	{
+		//Lee:
+		//The original was just too strange, though correct:
+		//	TiXmlString().swap(*this);
+		//Instead use the quit & re-init:
+		quit();
+		init(0,0);
+	}
+
+	/*	Function to reserve a big amount of data when we know we'll need it. Be aware that this
+		function DOES NOT clear the content of the TiXmlString if any exists.
+	*/
+	void reserve (size_type cap);
+
+	TiXmlString& assign (const char* str, size_type len);
+
+	TiXmlString& append (const char* str, size_type len);
+
+	void swap (TiXmlString& other)
+	{
+		Rep* r = rep_;
+		rep_ = other.rep_;
+		other.rep_ = r;
+	}
+
+  private:
+
+	void init(size_type sz) { init(sz, sz); }
+	void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; }
+	char* start() const { return rep_->str; }
+	char* finish() const { return rep_->str + rep_->size; }
+
+	struct Rep
+	{
+		size_type size, capacity;
+		char str[1];
+	};
+
+	void init(size_type sz, size_type cap)
+	{
+		if (cap)
+		{
+			// Lee: the original form:
+			//	rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap));
+			// doesn't work in some cases of new being overloaded. Switching
+			// to the normal allocation, although use an 'int' for systems
+			// that are overly picky about structure alignment.
+			const size_type bytesNeeded = sizeof(Rep) + cap;
+			const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); 
+			rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] );
+
+			rep_->str[ rep_->size = sz ] = '\0';
+			rep_->capacity = cap;
+		}
+		else
+		{
+			rep_ = &nullrep_;
+		}
+	}
+
+	void quit()
+	{
+		if (rep_ != &nullrep_)
+		{
+			// The rep_ is really an array of ints. (see the allocator, above).
+			// Cast it back before delete, so the compiler won't incorrectly call destructors.
+			delete [] ( reinterpret_cast<int*>( rep_ ) );
+		}
+	}
+
+	Rep * rep_;
+	static Rep nullrep_;
+
+} ;
+
+
+inline bool operator == (const TiXmlString & a, const TiXmlString & b)
+{
+	return    ( a.length() == b.length() )				// optimization on some platforms
+	       && ( strcmp(a.c_str(), b.c_str()) == 0 );	// actual compare
+}
+inline bool operator < (const TiXmlString & a, const TiXmlString & b)
+{
+	return strcmp(a.c_str(), b.c_str()) < 0;
+}
+
+inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); }
+inline bool operator >  (const TiXmlString & a, const TiXmlString & b) { return b < a; }
+inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); }
+inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); }
+
+inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; }
+inline bool operator == (const char* a, const TiXmlString & b) { return b == a; }
+inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); }
+inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); }
+
+TiXmlString operator + (const TiXmlString & a, const TiXmlString & b);
+TiXmlString operator + (const TiXmlString & a, const char* b);
+TiXmlString operator + (const char* a, const TiXmlString & b);
+
+
+/*
+   TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.
+   Only the operators that we need for TinyXML have been developped.
+*/
+class TiXmlOutStream : public TiXmlString
+{
+public :
+
+	// TiXmlOutStream << operator.
+	TiXmlOutStream & operator << (const TiXmlString & in)
+	{
+		*this += in;
+		return *this;
+	}
+
+	// TiXmlOutStream << operator.
+	TiXmlOutStream & operator << (const char * in)
+	{
+		*this += in;
+		return *this;
+	}
+
+} ;
+
+#endif	// TIXML_STRING_INCLUDED
+#endif	// TIXML_USE_STL
diff --git a/cpp/src/test/tinyxml/tinyxml.cpp b/cpp/src/test/tinyxml/tinyxml.cpp
new file mode 100644
index 0000000..9c161df
--- /dev/null
+++ b/cpp/src/test/tinyxml/tinyxml.cpp
@@ -0,0 +1,1886 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original code by Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#include <ctype.h>
+
+#ifdef TIXML_USE_STL
+#include <sstream>
+#include <iostream>
+#endif
+
+#include "tinyxml.h"
+
+FILE* TiXmlFOpen( const char* filename, const char* mode );
+
+bool TiXmlBase::condenseWhiteSpace = true;
+
+// Microsoft compiler security
+FILE* TiXmlFOpen( const char* filename, const char* mode )
+{
+	#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+		FILE* fp = 0;
+		errno_t err = fopen_s( &fp, filename, mode );
+		if ( !err && fp )
+			return fp;
+		return 0;
+	#else
+		return fopen( filename, mode );
+	#endif
+}
+
+void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString )
+{
+	int i=0;
+
+	while( i<(int)str.length() )
+	{
+		unsigned char c = (unsigned char) str[i];
+
+		if (    c == '&' 
+		     && i < ( (int)str.length() - 2 )
+			 && str[i+1] == '#'
+			 && str[i+2] == 'x' )
+		{
+			// Hexadecimal character reference.
+			// Pass through unchanged.
+			// &#xA9;	-- copyright symbol, for example.
+			//
+			// The -1 is a bug fix from Rob Laveaux. It keeps
+			// an overflow from happening if there is no ';'.
+			// There are actually 2 ways to exit this loop -
+			// while fails (error case) and break (semicolon found).
+			// However, there is no mechanism (currently) for
+			// this function to return an error.
+			while ( i<(int)str.length()-1 )
+			{
+				outString->append( str.c_str() + i, 1 );
+				++i;
+				if ( str[i] == ';' )
+					break;
+			}
+		}
+		else if ( c == '&' )
+		{
+			outString->append( entity[0].str, entity[0].strLength );
+			++i;
+		}
+		else if ( c == '<' )
+		{
+			outString->append( entity[1].str, entity[1].strLength );
+			++i;
+		}
+		else if ( c == '>' )
+		{
+			outString->append( entity[2].str, entity[2].strLength );
+			++i;
+		}
+		else if ( c == '\"' )
+		{
+			outString->append( entity[3].str, entity[3].strLength );
+			++i;
+		}
+		else if ( c == '\'' )
+		{
+			outString->append( entity[4].str, entity[4].strLength );
+			++i;
+		}
+		else if ( c < 32 )
+		{
+			// Easy pass at non-alpha/numeric/symbol
+			// Below 32 is symbolic.
+			char buf[ 32 ];
+			
+			#if defined(TIXML_SNPRINTF)		
+				TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) );
+			#else
+				sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) );
+			#endif		
+
+			//*ME:	warning C4267: convert 'size_t' to 'int'
+			//*ME:	Int-Cast to make compiler happy ...
+			outString->append( buf, (int)strlen( buf ) );
+			++i;
+		}
+		else
+		{
+			//char realc = (char) c;
+			//outString->append( &realc, 1 );
+			*outString += (char) c;	// somewhat more efficient function call.
+			++i;
+		}
+	}
+}
+
+
+TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase()
+{
+	parent = 0;
+	type = _type;
+	firstChild = 0;
+	lastChild = 0;
+	prev = 0;
+	next = 0;
+}
+
+
+TiXmlNode::~TiXmlNode()
+{
+	TiXmlNode* node = firstChild;
+	TiXmlNode* temp = 0;
+
+	while ( node )
+	{
+		temp = node;
+		node = node->next;
+		delete temp;
+	}	
+}
+
+
+void TiXmlNode::CopyTo( TiXmlNode* target ) const
+{
+	target->SetValue (value.c_str() );
+	target->userData = userData; 
+	target->location = location;
+}
+
+
+void TiXmlNode::Clear()
+{
+	TiXmlNode* node = firstChild;
+	TiXmlNode* temp = 0;
+
+	while ( node )
+	{
+		temp = node;
+		node = node->next;
+		delete temp;
+	}	
+
+	firstChild = 0;
+	lastChild = 0;
+}
+
+
+TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
+{
+	assert( node->parent == 0 || node->parent == this );
+	assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() );
+
+	if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT )
+	{
+		delete node;
+		if ( GetDocument() ) 
+			GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return 0;
+	}
+
+	node->parent = this;
+
+	node->prev = lastChild;
+	node->next = 0;
+
+	if ( lastChild )
+		lastChild->next = node;
+	else
+		firstChild = node;			// it was an empty list.
+
+	lastChild = node;
+	return node;
+}
+
+
+TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
+{
+	if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT )
+	{
+		if ( GetDocument() ) 
+			GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return 0;
+	}
+	TiXmlNode* node = addThis.Clone();
+	if ( !node )
+		return 0;
+
+	return LinkEndChild( node );
+}
+
+
+TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
+{	
+	if ( !beforeThis || beforeThis->parent != this ) {
+		return 0;
+	}
+	if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT )
+	{
+		if ( GetDocument() ) 
+			GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return 0;
+	}
+
+	TiXmlNode* node = addThis.Clone();
+	if ( !node )
+		return 0;
+	node->parent = this;
+
+	node->next = beforeThis;
+	node->prev = beforeThis->prev;
+	if ( beforeThis->prev )
+	{
+		beforeThis->prev->next = node;
+	}
+	else
+	{
+		assert( firstChild == beforeThis );
+		firstChild = node;
+	}
+	beforeThis->prev = node;
+	return node;
+}
+
+
+TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
+{
+	if ( !afterThis || afterThis->parent != this ) {
+		return 0;
+	}
+	if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT )
+	{
+		if ( GetDocument() ) 
+			GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return 0;
+	}
+
+	TiXmlNode* node = addThis.Clone();
+	if ( !node )
+		return 0;
+	node->parent = this;
+
+	node->prev = afterThis;
+	node->next = afterThis->next;
+	if ( afterThis->next )
+	{
+		afterThis->next->prev = node;
+	}
+	else
+	{
+		assert( lastChild == afterThis );
+		lastChild = node;
+	}
+	afterThis->next = node;
+	return node;
+}
+
+
+TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
+{
+	if ( !replaceThis )
+		return 0;
+
+	if ( replaceThis->parent != this )
+		return 0;
+
+	if ( withThis.ToDocument() ) {
+		// A document can never be a child.	Thanks to Noam.
+		TiXmlDocument* document = GetDocument();
+		if ( document ) 
+			document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return 0;
+	}
+
+	TiXmlNode* node = withThis.Clone();
+	if ( !node )
+		return 0;
+
+	node->next = replaceThis->next;
+	node->prev = replaceThis->prev;
+
+	if ( replaceThis->next )
+		replaceThis->next->prev = node;
+	else
+		lastChild = node;
+
+	if ( replaceThis->prev )
+		replaceThis->prev->next = node;
+	else
+		firstChild = node;
+
+	delete replaceThis;
+	node->parent = this;
+	return node;
+}
+
+
+bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
+{
+	if ( !removeThis ) {
+		return false;
+	}
+
+	if ( removeThis->parent != this )
+	{	
+		assert( 0 );
+		return false;
+	}
+
+	if ( removeThis->next )
+		removeThis->next->prev = removeThis->prev;
+	else
+		lastChild = removeThis->prev;
+
+	if ( removeThis->prev )
+		removeThis->prev->next = removeThis->next;
+	else
+		firstChild = removeThis->next;
+
+	delete removeThis;
+	return true;
+}
+
+const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const
+{
+	const TiXmlNode* node;
+	for ( node = firstChild; node; node = node->next )
+	{
+		if ( strcmp( node->Value(), _value ) == 0 )
+			return node;
+	}
+	return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const
+{
+	const TiXmlNode* node;
+	for ( node = lastChild; node; node = node->prev )
+	{
+		if ( strcmp( node->Value(), _value ) == 0 )
+			return node;
+	}
+	return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const
+{
+	if ( !previous )
+	{
+		return FirstChild();
+	}
+	else
+	{
+		assert( previous->parent == this );
+		return previous->NextSibling();
+	}
+}
+
+
+const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const
+{
+	if ( !previous )
+	{
+		return FirstChild( val );
+	}
+	else
+	{
+		assert( previous->parent == this );
+		return previous->NextSibling( val );
+	}
+}
+
+
+const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const 
+{
+	const TiXmlNode* node;
+	for ( node = next; node; node = node->next )
+	{
+		if ( strcmp( node->Value(), _value ) == 0 )
+			return node;
+	}
+	return 0;
+}
+
+
+const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const
+{
+	const TiXmlNode* node;
+	for ( node = prev; node; node = node->prev )
+	{
+		if ( strcmp( node->Value(), _value ) == 0 )
+			return node;
+	}
+	return 0;
+}
+
+
+void TiXmlElement::RemoveAttribute( const char * name )
+{
+    #ifdef TIXML_USE_STL
+	TIXML_STRING str( name );
+	TiXmlAttribute* node = attributeSet.Find( str );
+	#else
+	TiXmlAttribute* node = attributeSet.Find( name );
+	#endif
+	if ( node )
+	{
+		attributeSet.Remove( node );
+		delete node;
+	}
+}
+
+const TiXmlElement* TiXmlNode::FirstChildElement() const
+{
+	const TiXmlNode* node;
+
+	for (	node = FirstChild();
+			node;
+			node = node->NextSibling() )
+	{
+		if ( node->ToElement() )
+			return node->ToElement();
+	}
+	return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const
+{
+	const TiXmlNode* node;
+
+	for (	node = FirstChild( _value );
+			node;
+			node = node->NextSibling( _value ) )
+	{
+		if ( node->ToElement() )
+			return node->ToElement();
+	}
+	return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::NextSiblingElement() const
+{
+	const TiXmlNode* node;
+
+	for (	node = NextSibling();
+			node;
+			node = node->NextSibling() )
+	{
+		if ( node->ToElement() )
+			return node->ToElement();
+	}
+	return 0;
+}
+
+
+const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const
+{
+	const TiXmlNode* node;
+
+	for (	node = NextSibling( _value );
+			node;
+			node = node->NextSibling( _value ) )
+	{
+		if ( node->ToElement() )
+			return node->ToElement();
+	}
+	return 0;
+}
+
+
+const TiXmlDocument* TiXmlNode::GetDocument() const
+{
+	const TiXmlNode* node;
+
+	for( node = this; node; node = node->parent )
+	{
+		if ( node->ToDocument() )
+			return node->ToDocument();
+	}
+	return 0;
+}
+
+
+TiXmlElement::TiXmlElement (const char * _value)
+	: TiXmlNode( TiXmlNode::TINYXML_ELEMENT )
+{
+	firstChild = lastChild = 0;
+	value = _value;
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlElement::TiXmlElement( const std::string& _value ) 
+	: TiXmlNode( TiXmlNode::TINYXML_ELEMENT )
+{
+	firstChild = lastChild = 0;
+	value = _value;
+}
+#endif
+
+
+TiXmlElement::TiXmlElement( const TiXmlElement& copy)
+	: TiXmlNode( TiXmlNode::TINYXML_ELEMENT )
+{
+	firstChild = lastChild = 0;
+	copy.CopyTo( this );	
+}
+
+
+TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base )
+{
+	ClearThis();
+	base.CopyTo( this );
+	return *this;
+}
+
+
+TiXmlElement::~TiXmlElement()
+{
+	ClearThis();
+}
+
+
+void TiXmlElement::ClearThis()
+{
+	Clear();
+	while( attributeSet.First() )
+	{
+		TiXmlAttribute* node = attributeSet.First();
+		attributeSet.Remove( node );
+		delete node;
+	}
+}
+
+
+const char* TiXmlElement::Attribute( const char* name ) const
+{
+	const TiXmlAttribute* node = attributeSet.Find( name );
+	if ( node )
+		return node->Value();
+	return 0;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name ) const
+{
+	const TiXmlAttribute* attrib = attributeSet.Find( name );
+	if ( attrib )
+		return &attrib->ValueStr();
+	return 0;
+}
+#endif
+
+
+const char* TiXmlElement::Attribute( const char* name, int* i ) const
+{
+	const TiXmlAttribute* attrib = attributeSet.Find( name );
+	const char* result = 0;
+
+	if ( attrib ) {
+		result = attrib->Value();
+		if ( i ) {
+			attrib->QueryIntValue( i );
+		}
+	}
+	return result;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const
+{
+	const TiXmlAttribute* attrib = attributeSet.Find( name );
+	const std::string* result = 0;
+
+	if ( attrib ) {
+		result = &attrib->ValueStr();
+		if ( i ) {
+			attrib->QueryIntValue( i );
+		}
+	}
+	return result;
+}
+#endif
+
+
+const char* TiXmlElement::Attribute( const char* name, double* d ) const
+{
+	const TiXmlAttribute* attrib = attributeSet.Find( name );
+	const char* result = 0;
+
+	if ( attrib ) {
+		result = attrib->Value();
+		if ( d ) {
+			attrib->QueryDoubleValue( d );
+		}
+	}
+	return result;
+}
+
+
+#ifdef TIXML_USE_STL
+const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const
+{
+	const TiXmlAttribute* attrib = attributeSet.Find( name );
+	const std::string* result = 0;
+
+	if ( attrib ) {
+		result = &attrib->ValueStr();
+		if ( d ) {
+			attrib->QueryDoubleValue( d );
+		}
+	}
+	return result;
+}
+#endif
+
+
+int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
+{
+	const TiXmlAttribute* attrib = attributeSet.Find( name );
+	if ( !attrib )
+		return TIXML_NO_ATTRIBUTE;
+	return attrib->QueryIntValue( ival );
+}
+
+
+int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const
+{
+	const TiXmlAttribute* node = attributeSet.Find( name );
+	if ( !node )
+		return TIXML_NO_ATTRIBUTE;
+
+	int ival = 0;
+	int result = node->QueryIntValue( &ival );
+	*value = (unsigned)ival;
+	return result;
+}
+
+
+int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const
+{
+	const TiXmlAttribute* node = attributeSet.Find( name );
+	if ( !node )
+		return TIXML_NO_ATTRIBUTE;
+	
+	int result = TIXML_WRONG_TYPE;
+	if (    StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) 
+		 || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) 
+		 || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) 
+	{
+		*bval = true;
+		result = TIXML_SUCCESS;
+	}
+	else if (    StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) 
+			  || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) 
+			  || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) 
+	{
+		*bval = false;
+		result = TIXML_SUCCESS;
+	}
+	return result;
+}
+
+
+
+#ifdef TIXML_USE_STL
+int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const
+{
+	const TiXmlAttribute* attrib = attributeSet.Find( name );
+	if ( !attrib )
+		return TIXML_NO_ATTRIBUTE;
+	return attrib->QueryIntValue( ival );
+}
+#endif
+
+
+int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const
+{
+	const TiXmlAttribute* attrib = attributeSet.Find( name );
+	if ( !attrib )
+		return TIXML_NO_ATTRIBUTE;
+	return attrib->QueryDoubleValue( dval );
+}
+
+
+#ifdef TIXML_USE_STL
+int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const
+{
+	const TiXmlAttribute* attrib = attributeSet.Find( name );
+	if ( !attrib )
+		return TIXML_NO_ATTRIBUTE;
+	return attrib->QueryDoubleValue( dval );
+}
+#endif
+
+
+void TiXmlElement::SetAttribute( const char * name, int val )
+{	
+	TiXmlAttribute* attrib = attributeSet.FindOrCreate( name );
+	if ( attrib ) {
+		attrib->SetIntValue( val );
+	}
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlElement::SetAttribute( const std::string& name, int val )
+{	
+	TiXmlAttribute* attrib = attributeSet.FindOrCreate( name );
+	if ( attrib ) {
+		attrib->SetIntValue( val );
+	}
+}
+#endif
+
+
+void TiXmlElement::SetDoubleAttribute( const char * name, double val )
+{	
+	TiXmlAttribute* attrib = attributeSet.FindOrCreate( name );
+	if ( attrib ) {
+		attrib->SetDoubleValue( val );
+	}
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlElement::SetDoubleAttribute( const std::string& name, double val )
+{	
+	TiXmlAttribute* attrib = attributeSet.FindOrCreate( name );
+	if ( attrib ) {
+		attrib->SetDoubleValue( val );
+	}
+}
+#endif 
+
+
+void TiXmlElement::SetAttribute( const char * cname, const char * cvalue )
+{
+	TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname );
+	if ( attrib ) {
+		attrib->SetValue( cvalue );
+	}
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value )
+{
+	TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name );
+	if ( attrib ) {
+		attrib->SetValue( _value );
+	}
+}
+#endif
+
+
+void TiXmlElement::Print( FILE* cfile, int depth ) const
+{
+	int i;
+	assert( cfile );
+	for ( i=0; i<depth; i++ ) {
+		fprintf( cfile, "    " );
+	}
+
+	fprintf( cfile, "<%s", value.c_str() );
+
+	const TiXmlAttribute* attrib;
+	for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
+	{
+		fprintf( cfile, " " );
+		attrib->Print( cfile, depth );
+	}
+
+	// There are 3 different formatting approaches:
+	// 1) An element without children is printed as a <foo /> node
+	// 2) An element with only a text child is printed as <foo> text </foo>
+	// 3) An element with children is printed on multiple lines.
+	TiXmlNode* node;
+	if ( !firstChild )
+	{
+		fprintf( cfile, " />" );
+	}
+	else if ( firstChild == lastChild && firstChild->ToText() )
+	{
+		fprintf( cfile, ">" );
+		firstChild->Print( cfile, depth + 1 );
+		fprintf( cfile, "</%s>", value.c_str() );
+	}
+	else
+	{
+		fprintf( cfile, ">" );
+
+		for ( node = firstChild; node; node=node->NextSibling() )
+		{
+			if ( !node->ToText() )
+			{
+				fprintf( cfile, "\n" );
+			}
+			node->Print( cfile, depth+1 );
+		}
+		fprintf( cfile, "\n" );
+		for( i=0; i<depth; ++i ) {
+			fprintf( cfile, "    " );
+		}
+		fprintf( cfile, "</%s>", value.c_str() );
+	}
+}
+
+
+void TiXmlElement::CopyTo( TiXmlElement* target ) const
+{
+	// superclass:
+	TiXmlNode::CopyTo( target );
+
+	// Element class: 
+	// Clone the attributes, then clone the children.
+	const TiXmlAttribute* attribute = 0;
+	for(	attribute = attributeSet.First();
+	attribute;
+	attribute = attribute->Next() )
+	{
+		target->SetAttribute( attribute->Name(), attribute->Value() );
+	}
+
+	TiXmlNode* node = 0;
+	for ( node = firstChild; node; node = node->NextSibling() )
+	{
+		target->LinkEndChild( node->Clone() );
+	}
+}
+
+bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const
+{
+	if ( visitor->VisitEnter( *this, attributeSet.First() ) ) 
+	{
+		for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+		{
+			if ( !node->Accept( visitor ) )
+				break;
+		}
+	}
+	return visitor->VisitExit( *this );
+}
+
+
+TiXmlNode* TiXmlElement::Clone() const
+{
+	TiXmlElement* clone = new TiXmlElement( Value() );
+	if ( !clone )
+		return 0;
+
+	CopyTo( clone );
+	return clone;
+}
+
+
+const char* TiXmlElement::GetText() const
+{
+	const TiXmlNode* child = this->FirstChild();
+	if ( child ) {
+		const TiXmlText* childText = child->ToText();
+		if ( childText ) {
+			return childText->Value();
+		}
+	}
+	return 0;
+}
+
+
+TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )
+{
+	tabsize = 4;
+	useMicrosoftBOM = false;
+	ClearError();
+}
+
+TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )
+{
+	tabsize = 4;
+	useMicrosoftBOM = false;
+	value = documentName;
+	ClearError();
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )
+{
+	tabsize = 4;
+	useMicrosoftBOM = false;
+    value = documentName;
+	ClearError();
+}
+#endif
+
+
+TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT )
+{
+	copy.CopyTo( this );
+}
+
+
+TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy )
+{
+	Clear();
+	copy.CopyTo( this );
+	return *this;
+}
+
+
+bool TiXmlDocument::LoadFile( TiXmlEncoding encoding )
+{
+	return LoadFile( Value(), encoding );
+}
+
+
+bool TiXmlDocument::SaveFile() const
+{
+	return SaveFile( Value() );
+}
+
+bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
+{
+	TIXML_STRING filename( _filename );
+	value = filename;
+
+	// reading in binary mode so that tinyxml can normalize the EOL
+	FILE* file = TiXmlFOpen( value.c_str (), "rb" );	
+
+	if ( file )
+	{
+		bool result = LoadFile( file, encoding );
+		fclose( file );
+		return result;
+	}
+	else
+	{
+		SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return false;
+	}
+}
+
+bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
+{
+	if ( !file ) 
+	{
+		SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return false;
+	}
+
+	// Delete the existing data:
+	Clear();
+	location.Clear();
+
+	// Get the file size, so we can pre-allocate the string. HUGE speed impact.
+	long length = 0;
+	fseek( file, 0, SEEK_END );
+	length = ftell( file );
+	fseek( file, 0, SEEK_SET );
+
+	// Strange case, but good to handle up front.
+	if ( length <= 0 )
+	{
+		SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return false;
+	}
+
+	// Subtle bug here. TinyXml did use fgets. But from the XML spec:
+	// 2.11 End-of-Line Handling
+	// <snip>
+	// <quote>
+	// ...the XML processor MUST behave as if it normalized all line breaks in external 
+	// parsed entities (including the document entity) on input, before parsing, by translating 
+	// both the two-character sequence #xD #xA and any #xD that is not followed by #xA to 
+	// a single #xA character.
+	// </quote>
+	//
+	// It is not clear fgets does that, and certainly isn't clear it works cross platform. 
+	// Generally, you expect fgets to translate from the convention of the OS to the c/unix
+	// convention, and not work generally.
+
+	/*
+	while( fgets( buf, sizeof(buf), file ) )
+	{
+		data += buf;
+	}
+	*/
+
+	char* buf = new char[ length+1 ];
+	buf[0] = 0;
+
+	if ( fread( buf, length, 1, file ) != 1 ) {
+		delete [] buf;
+		SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return false;
+	}
+
+	// Process the buffer in place to normalize new lines. (See comment above.)
+	// Copies from the 'p' to 'q' pointer, where p can advance faster if
+	// a newline-carriage return is hit.
+	//
+	// Wikipedia:
+	// Systems based on ASCII or a compatible character set use either LF  (Line feed, '\n', 0x0A, 10 in decimal) or 
+	// CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)...
+	//		* LF:    Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others
+    //		* CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS
+    //		* CR:    Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9
+
+	const char* p = buf;	// the read head
+	char* q = buf;			// the write head
+	const char CR = 0x0d;
+	const char LF = 0x0a;
+
+	buf[length] = 0;
+	while( *p ) {
+		assert( p < (buf+length) );
+		assert( q <= (buf+length) );
+		assert( q <= p );
+
+		if ( *p == CR ) {
+			*q++ = LF;
+			p++;
+			if ( *p == LF ) {		// check for CR+LF (and skip LF)
+				p++;
+			}
+		}
+		else {
+			*q++ = *p++;
+		}
+	}
+	assert( q <= (buf+length) );
+	*q = 0;
+
+	Parse( buf, 0, encoding );
+
+	delete [] buf;
+	return !Error();
+}
+
+
+bool TiXmlDocument::SaveFile( const char * filename ) const
+{
+	// The old c stuff lives on...
+	FILE* fp = TiXmlFOpen( filename, "w" );
+	if ( fp )
+	{
+		bool result = SaveFile( fp );
+		fclose( fp );
+		return result;
+	}
+	return false;
+}
+
+
+bool TiXmlDocument::SaveFile( FILE* fp ) const
+{
+	if ( useMicrosoftBOM ) 
+	{
+		const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+		const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+		const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+		fputc( TIXML_UTF_LEAD_0, fp );
+		fputc( TIXML_UTF_LEAD_1, fp );
+		fputc( TIXML_UTF_LEAD_2, fp );
+	}
+	Print( fp, 0 );
+	return (ferror(fp) == 0);
+}
+
+
+void TiXmlDocument::CopyTo( TiXmlDocument* target ) const
+{
+	TiXmlNode::CopyTo( target );
+
+	target->error = error;
+	target->errorId = errorId;
+	target->errorDesc = errorDesc;
+	target->tabsize = tabsize;
+	target->errorLocation = errorLocation;
+	target->useMicrosoftBOM = useMicrosoftBOM;
+
+	TiXmlNode* node = 0;
+	for ( node = firstChild; node; node = node->NextSibling() )
+	{
+		target->LinkEndChild( node->Clone() );
+	}	
+}
+
+
+TiXmlNode* TiXmlDocument::Clone() const
+{
+	TiXmlDocument* clone = new TiXmlDocument();
+	if ( !clone )
+		return 0;
+
+	CopyTo( clone );
+	return clone;
+}
+
+
+void TiXmlDocument::Print( FILE* cfile, int depth ) const
+{
+	assert( cfile );
+	for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+	{
+		node->Print( cfile, depth );
+		fprintf( cfile, "\n" );
+	}
+}
+
+
+bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const
+{
+	if ( visitor->VisitEnter( *this ) )
+	{
+		for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
+		{
+			if ( !node->Accept( visitor ) )
+				break;
+		}
+	}
+	return visitor->VisitExit( *this );
+}
+
+
+const TiXmlAttribute* TiXmlAttribute::Next() const
+{
+	// We are using knowledge of the sentinel. The sentinel
+	// have a value or name.
+	if ( next->value.empty() && next->name.empty() )
+		return 0;
+	return next;
+}
+
+/*
+TiXmlAttribute* TiXmlAttribute::Next()
+{
+	// We are using knowledge of the sentinel. The sentinel
+	// have a value or name.
+	if ( next->value.empty() && next->name.empty() )
+		return 0;
+	return next;
+}
+*/
+
+const TiXmlAttribute* TiXmlAttribute::Previous() const
+{
+	// We are using knowledge of the sentinel. The sentinel
+	// have a value or name.
+	if ( prev->value.empty() && prev->name.empty() )
+		return 0;
+	return prev;
+}
+
+/*
+TiXmlAttribute* TiXmlAttribute::Previous()
+{
+	// We are using knowledge of the sentinel. The sentinel
+	// have a value or name.
+	if ( prev->value.empty() && prev->name.empty() )
+		return 0;
+	return prev;
+}
+*/
+
+void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
+{
+	TIXML_STRING n, v;
+
+	EncodeString( name, &n );
+	EncodeString( value, &v );
+
+	if (value.find ('\"') == TIXML_STRING::npos) {
+		if ( cfile ) {
+			fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
+		}
+		if ( str ) {
+			(*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\"";
+		}
+	}
+	else {
+		if ( cfile ) {
+			fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
+		}
+		if ( str ) {
+			(*str) += n; (*str) += "='"; (*str) += v; (*str) += "'";
+		}
+	}
+}
+
+
+int TiXmlAttribute::QueryIntValue( int* ival ) const
+{
+	if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 )
+		return TIXML_SUCCESS;
+	return TIXML_WRONG_TYPE;
+}
+
+int TiXmlAttribute::QueryDoubleValue( double* dval ) const
+{
+	if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 )
+		return TIXML_SUCCESS;
+	return TIXML_WRONG_TYPE;
+}
+
+void TiXmlAttribute::SetIntValue( int _value )
+{
+	char buf [64];
+	#if defined(TIXML_SNPRINTF)		
+		TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value);
+	#else
+		sprintf (buf, "%d", _value);
+	#endif
+	SetValue (buf);
+}
+
+void TiXmlAttribute::SetDoubleValue( double _value )
+{
+	char buf [256];
+	#if defined(TIXML_SNPRINTF)		
+		TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value);
+	#else
+		sprintf (buf, "%g", _value);
+	#endif
+	SetValue (buf);
+}
+
+int TiXmlAttribute::IntValue() const
+{
+	return atoi (value.c_str ());
+}
+
+double  TiXmlAttribute::DoubleValue() const
+{
+	return atof (value.c_str ());
+}
+
+
+TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT )
+{
+	copy.CopyTo( this );
+}
+
+
+TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base )
+{
+	Clear();
+	base.CopyTo( this );
+	return *this;
+}
+
+
+void TiXmlComment::Print( FILE* cfile, int depth ) const
+{
+	assert( cfile );
+	for ( int i=0; i<depth; i++ )
+	{
+		fprintf( cfile,  "    " );
+	}
+	fprintf( cfile, "<!--%s-->", value.c_str() );
+}
+
+
+void TiXmlComment::CopyTo( TiXmlComment* target ) const
+{
+	TiXmlNode::CopyTo( target );
+}
+
+
+bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const
+{
+	return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlComment::Clone() const
+{
+	TiXmlComment* clone = new TiXmlComment();
+
+	if ( !clone )
+		return 0;
+
+	CopyTo( clone );
+	return clone;
+}
+
+
+void TiXmlText::Print( FILE* cfile, int depth ) const
+{
+	assert( cfile );
+	if ( cdata )
+	{
+		int i;
+		fprintf( cfile, "\n" );
+		for ( i=0; i<depth; i++ ) {
+			fprintf( cfile, "    " );
+		}
+		fprintf( cfile, "<![CDATA[%s]]>\n", value.c_str() );	// unformatted output
+	}
+	else
+	{
+		TIXML_STRING buffer;
+		EncodeString( value, &buffer );
+		fprintf( cfile, "%s", buffer.c_str() );
+	}
+}
+
+
+void TiXmlText::CopyTo( TiXmlText* target ) const
+{
+	TiXmlNode::CopyTo( target );
+	target->cdata = cdata;
+}
+
+
+bool TiXmlText::Accept( TiXmlVisitor* visitor ) const
+{
+	return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlText::Clone() const
+{	
+	TiXmlText* clone = 0;
+	clone = new TiXmlText( "" );
+
+	if ( !clone )
+		return 0;
+
+	CopyTo( clone );
+	return clone;
+}
+
+
+TiXmlDeclaration::TiXmlDeclaration( const char * _version,
+									const char * _encoding,
+									const char * _standalone )
+	: TiXmlNode( TiXmlNode::TINYXML_DECLARATION )
+{
+	version = _version;
+	encoding = _encoding;
+	standalone = _standalone;
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlDeclaration::TiXmlDeclaration(	const std::string& _version,
+									const std::string& _encoding,
+									const std::string& _standalone )
+	: TiXmlNode( TiXmlNode::TINYXML_DECLARATION )
+{
+	version = _version;
+	encoding = _encoding;
+	standalone = _standalone;
+}
+#endif
+
+
+TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )
+	: TiXmlNode( TiXmlNode::TINYXML_DECLARATION )
+{
+	copy.CopyTo( this );	
+}
+
+
+TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )
+{
+	Clear();
+	copy.CopyTo( this );
+	return *this;
+}
+
+
+void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
+{
+	if ( cfile ) fprintf( cfile, "<?xml " );
+	if ( str )	 (*str) += "<?xml ";
+
+	if ( !version.empty() ) {
+		if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ());
+		if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; }
+	}
+	if ( !encoding.empty() ) {
+		if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ());
+		if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; }
+	}
+	if ( !standalone.empty() ) {
+		if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ());
+		if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; }
+	}
+	if ( cfile ) fprintf( cfile, "?>" );
+	if ( str )	 (*str) += "?>";
+}
+
+
+void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const
+{
+	TiXmlNode::CopyTo( target );
+
+	target->version = version;
+	target->encoding = encoding;
+	target->standalone = standalone;
+}
+
+
+bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const
+{
+	return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlDeclaration::Clone() const
+{	
+	TiXmlDeclaration* clone = new TiXmlDeclaration();
+
+	if ( !clone )
+		return 0;
+
+	CopyTo( clone );
+	return clone;
+}
+
+
+void TiXmlUnknown::Print( FILE* cfile, int depth ) const
+{
+	for ( int i=0; i<depth; i++ )
+		fprintf( cfile, "    " );
+	fprintf( cfile, "<%s>", value.c_str() );
+}
+
+
+void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const
+{
+	TiXmlNode::CopyTo( target );
+}
+
+
+bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const
+{
+	return visitor->Visit( *this );
+}
+
+
+TiXmlNode* TiXmlUnknown::Clone() const
+{
+	TiXmlUnknown* clone = new TiXmlUnknown();
+
+	if ( !clone )
+		return 0;
+
+	CopyTo( clone );
+	return clone;
+}
+
+
+TiXmlAttributeSet::TiXmlAttributeSet()
+{
+	sentinel.next = &sentinel;
+	sentinel.prev = &sentinel;
+}
+
+
+TiXmlAttributeSet::~TiXmlAttributeSet()
+{
+	assert( sentinel.next == &sentinel );
+	assert( sentinel.prev == &sentinel );
+}
+
+
+void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
+{
+    #ifdef TIXML_USE_STL
+	assert( !Find( TIXML_STRING( addMe->Name() ) ) );	// Shouldn't be multiply adding to the set.
+	#else
+	assert( !Find( addMe->Name() ) );	// Shouldn't be multiply adding to the set.
+	#endif
+
+	addMe->next = &sentinel;
+	addMe->prev = sentinel.prev;
+
+	sentinel.prev->next = addMe;
+	sentinel.prev      = addMe;
+}
+
+void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
+{
+	TiXmlAttribute* node;
+
+	for( node = sentinel.next; node != &sentinel; node = node->next )
+	{
+		if ( node == removeMe )
+		{
+			node->prev->next = node->next;
+			node->next->prev = node->prev;
+			node->next = 0;
+			node->prev = 0;
+			return;
+		}
+	}
+	assert( 0 );		// we tried to remove a non-linked attribute.
+}
+
+
+#ifdef TIXML_USE_STL
+TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const
+{
+	for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+	{
+		if ( node->name == name )
+			return node;
+	}
+	return 0;
+}
+
+TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name )
+{
+	TiXmlAttribute* attrib = Find( _name );
+	if ( !attrib ) {
+		attrib = new TiXmlAttribute();
+		Add( attrib );
+		attrib->SetName( _name );
+	}
+	return attrib;
+}
+#endif
+
+
+TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const
+{
+	for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
+	{
+		if ( strcmp( node->name.c_str(), name ) == 0 )
+			return node;
+	}
+	return 0;
+}
+
+
+TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name )
+{
+	TiXmlAttribute* attrib = Find( _name );
+	if ( !attrib ) {
+		attrib = new TiXmlAttribute();
+		Add( attrib );
+		attrib->SetName( _name );
+	}
+	return attrib;
+}
+
+
+#ifdef TIXML_USE_STL	
+std::istream& operator>> (std::istream & in, TiXmlNode & base)
+{
+	TIXML_STRING tag;
+	tag.reserve( 8 * 1000 );
+	base.StreamIn( &in, &tag );
+
+	base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
+	return in;
+}
+#endif
+
+
+#ifdef TIXML_USE_STL	
+std::ostream& operator<< (std::ostream & out, const TiXmlNode & base)
+{
+	TiXmlPrinter printer;
+	printer.SetStreamPrinting();
+	base.Accept( &printer );
+	out << printer.Str();
+
+	return out;
+}
+
+
+std::string& operator<< (std::string& out, const TiXmlNode& base )
+{
+	TiXmlPrinter printer;
+	printer.SetStreamPrinting();
+	base.Accept( &printer );
+	out.append( printer.Str() );
+
+	return out;
+}
+#endif
+
+
+TiXmlHandle TiXmlHandle::FirstChild() const
+{
+	if ( node )
+	{
+		TiXmlNode* child = node->FirstChild();
+		if ( child )
+			return TiXmlHandle( child );
+	}
+	return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const
+{
+	if ( node )
+	{
+		TiXmlNode* child = node->FirstChild( value );
+		if ( child )
+			return TiXmlHandle( child );
+	}
+	return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChildElement() const
+{
+	if ( node )
+	{
+		TiXmlElement* child = node->FirstChildElement();
+		if ( child )
+			return TiXmlHandle( child );
+	}
+	return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const
+{
+	if ( node )
+	{
+		TiXmlElement* child = node->FirstChildElement( value );
+		if ( child )
+			return TiXmlHandle( child );
+	}
+	return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::Child( int count ) const
+{
+	if ( node )
+	{
+		int i;
+		TiXmlNode* child = node->FirstChild();
+		for (	i=0;
+				child && i<count;
+				child = child->NextSibling(), ++i )
+		{
+			// nothing
+		}
+		if ( child )
+			return TiXmlHandle( child );
+	}
+	return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const
+{
+	if ( node )
+	{
+		int i;
+		TiXmlNode* child = node->FirstChild( value );
+		for (	i=0;
+				child && i<count;
+				child = child->NextSibling( value ), ++i )
+		{
+			// nothing
+		}
+		if ( child )
+			return TiXmlHandle( child );
+	}
+	return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::ChildElement( int count ) const
+{
+	if ( node )
+	{
+		int i;
+		TiXmlElement* child = node->FirstChildElement();
+		for (	i=0;
+				child && i<count;
+				child = child->NextSiblingElement(), ++i )
+		{
+			// nothing
+		}
+		if ( child )
+			return TiXmlHandle( child );
+	}
+	return TiXmlHandle( 0 );
+}
+
+
+TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const
+{
+	if ( node )
+	{
+		int i;
+		TiXmlElement* child = node->FirstChildElement( value );
+		for (	i=0;
+				child && i<count;
+				child = child->NextSiblingElement( value ), ++i )
+		{
+			// nothing
+		}
+		if ( child )
+			return TiXmlHandle( child );
+	}
+	return TiXmlHandle( 0 );
+}
+
+
+bool TiXmlPrinter::VisitEnter( const TiXmlDocument& )
+{
+	return true;
+}
+
+bool TiXmlPrinter::VisitExit( const TiXmlDocument& )
+{
+	return true;
+}
+
+bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute )
+{
+	DoIndent();
+	buffer += "<";
+	buffer += element.Value();
+
+	for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() )
+	{
+		buffer += " ";
+		attrib->Print( 0, 0, &buffer );
+	}
+
+	if ( !element.FirstChild() ) 
+	{
+		buffer += " />";
+		DoLineBreak();
+	}
+	else 
+	{
+		buffer += ">";
+		if (    element.FirstChild()->ToText()
+			  && element.LastChild() == element.FirstChild()
+			  && element.FirstChild()->ToText()->CDATA() == false )
+		{
+			simpleTextPrint = true;
+			// no DoLineBreak()!
+		}
+		else
+		{
+			DoLineBreak();
+		}
+	}
+	++depth;	
+	return true;
+}
+
+
+bool TiXmlPrinter::VisitExit( const TiXmlElement& element )
+{
+	--depth;
+	if ( !element.FirstChild() ) 
+	{
+		// nothing.
+	}
+	else 
+	{
+		if ( simpleTextPrint )
+		{
+			simpleTextPrint = false;
+		}
+		else
+		{
+			DoIndent();
+		}
+		buffer += "</";
+		buffer += element.Value();
+		buffer += ">";
+		DoLineBreak();
+	}
+	return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlText& text )
+{
+	if ( text.CDATA() )
+	{
+		DoIndent();
+		buffer += "<![CDATA[";
+		buffer += text.Value();
+		buffer += "]]>";
+		DoLineBreak();
+	}
+	else if ( simpleTextPrint )
+	{
+		TIXML_STRING str;
+		TiXmlBase::EncodeString( text.ValueTStr(), &str );
+		buffer += str;
+	}
+	else
+	{
+		DoIndent();
+		TIXML_STRING str;
+		TiXmlBase::EncodeString( text.ValueTStr(), &str );
+		buffer += str;
+		DoLineBreak();
+	}
+	return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration )
+{
+	DoIndent();
+	declaration.Print( 0, 0, &buffer );
+	DoLineBreak();
+	return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlComment& comment )
+{
+	DoIndent();
+	buffer += "<!--";
+	buffer += comment.Value();
+	buffer += "-->";
+	DoLineBreak();
+	return true;
+}
+
+
+bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown )
+{
+	DoIndent();
+	buffer += "<";
+	buffer += unknown.Value();
+	buffer += ">";
+	DoLineBreak();
+	return true;
+}
+
diff --git a/cpp/src/test/tinyxml/tinyxml.h b/cpp/src/test/tinyxml/tinyxml.h
new file mode 100644
index 0000000..a3589e5
--- /dev/null
+++ b/cpp/src/test/tinyxml/tinyxml.h
@@ -0,0 +1,1805 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original code by Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it and
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+
+#ifndef TINYXML_INCLUDED
+#define TINYXML_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning( push )
+#pragma warning( disable : 4530 )
+#pragma warning( disable : 4786 )
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+// Help out windows:
+#if defined( _DEBUG ) && !defined( DEBUG )
+#define DEBUG
+#endif
+
+#ifdef TIXML_USE_STL
+	#include <string>
+ 	#include <iostream>
+	#include <sstream>
+	#define TIXML_STRING		std::string
+#else
+	#include "tinystr.h"
+	#define TIXML_STRING		TiXmlString
+#endif
+
+// Deprecated library function hell. Compilers want to use the
+// new safe versions. This probably doesn't fully address the problem,
+// but it gets closer. There are too many compilers for me to fully
+// test. If you get compilation troubles, undefine TIXML_SAFE
+#define TIXML_SAFE
+
+#ifdef TIXML_SAFE
+	#if defined(_MSC_VER) && (_MSC_VER >= 1400 )
+		// Microsoft visual studio, version 2005 and higher.
+		#define TIXML_SNPRINTF _snprintf_s
+		#define TIXML_SSCANF   sscanf_s
+	#elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
+		// Microsoft visual studio, version 6 and higher.
+		//#pragma message( "Using _sn* functions." )
+		#define TIXML_SNPRINTF _snprintf
+		#define TIXML_SSCANF   sscanf
+	#elif defined(__GNUC__) && (__GNUC__ >= 3 )
+		// GCC version 3 and higher.s
+		//#warning( "Using sn* functions." )
+		#define TIXML_SNPRINTF snprintf
+		#define TIXML_SSCANF   sscanf
+	#else
+		#define TIXML_SNPRINTF snprintf
+		#define TIXML_SSCANF   sscanf
+	#endif
+#endif	
+
+class TiXmlDocument;
+class TiXmlElement;
+class TiXmlComment;
+class TiXmlUnknown;
+class TiXmlAttribute;
+class TiXmlText;
+class TiXmlDeclaration;
+class TiXmlParsingData;
+
+const int TIXML_MAJOR_VERSION = 2;
+const int TIXML_MINOR_VERSION = 6;
+const int TIXML_PATCH_VERSION = 2;
+
+/*	Internal structure for tracking location of items 
+	in the XML file.
+*/
+struct TiXmlCursor
+{
+	TiXmlCursor()		{ Clear(); }
+	void Clear()		{ row = col = -1; }
+
+	int row;	// 0 based.
+	int col;	// 0 based.
+};
+
+
+/**
+	Implements the interface to the "Visitor pattern" (see the Accept() method.)
+	If you call the Accept() method, it requires being passed a TiXmlVisitor
+	class to handle callbacks. For nodes that contain other nodes (Document, Element)
+	you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
+	are simply called with Visit().
+
+	If you return 'true' from a Visit method, recursive parsing will continue. If you return
+	false, <b>no children of this node or its sibilings</b> will be Visited.
+
+	All flavors of Visit methods have a default implementation that returns 'true' (continue 
+	visiting). You need to only override methods that are interesting to you.
+
+	Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
+
+	You should never change the document from a callback.
+
+	@sa TiXmlNode::Accept()
+*/
+class TiXmlVisitor
+{
+public:
+	virtual ~TiXmlVisitor() {}
+
+	/// Visit a document.
+	virtual bool VisitEnter( const TiXmlDocument& /*doc*/ )			{ return true; }
+	/// Visit a document.
+	virtual bool VisitExit( const TiXmlDocument& /*doc*/ )			{ return true; }
+
+	/// Visit an element.
+	virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ )	{ return true; }
+	/// Visit an element.
+	virtual bool VisitExit( const TiXmlElement& /*element*/ )		{ return true; }
+
+	/// Visit a declaration
+	virtual bool Visit( const TiXmlDeclaration& /*declaration*/ )	{ return true; }
+	/// Visit a text node
+	virtual bool Visit( const TiXmlText& /*text*/ )					{ return true; }
+	/// Visit a comment node
+	virtual bool Visit( const TiXmlComment& /*comment*/ )			{ return true; }
+	/// Visit an unknown node
+	virtual bool Visit( const TiXmlUnknown& /*unknown*/ )			{ return true; }
+};
+
+// Only used by Attribute::Query functions
+enum 
+{ 
+	TIXML_SUCCESS,
+	TIXML_NO_ATTRIBUTE,
+	TIXML_WRONG_TYPE
+};
+
+
+// Used by the parsing routines.
+enum TiXmlEncoding
+{
+	TIXML_ENCODING_UNKNOWN,
+	TIXML_ENCODING_UTF8,
+	TIXML_ENCODING_LEGACY
+};
+
+const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN;
+
+/** TiXmlBase is a base class for every class in TinyXml.
+	It does little except to establish that TinyXml classes
+	can be printed and provide some utility functions.
+
+	In XML, the document and elements can contain
+	other elements and other types of nodes.
+
+	@verbatim
+	A Document can contain:	Element	(container or leaf)
+							Comment (leaf)
+							Unknown (leaf)
+							Declaration( leaf )
+
+	An Element can contain:	Element (container or leaf)
+							Text	(leaf)
+							Attributes (not on tree)
+							Comment (leaf)
+							Unknown (leaf)
+
+	A Decleration contains: Attributes (not on tree)
+	@endverbatim
+*/
+class TiXmlBase
+{
+	friend class TiXmlNode;
+	friend class TiXmlElement;
+	friend class TiXmlDocument;
+
+public:
+	TiXmlBase()	:	userData(0)		{}
+	virtual ~TiXmlBase()			{}
+
+	/**	All TinyXml classes can print themselves to a filestream
+		or the string class (TiXmlString in non-STL mode, std::string
+		in STL mode.) Either or both cfile and str can be null.
+		
+		This is a formatted print, and will insert 
+		tabs and newlines.
+		
+		(For an unformatted stream, use the << operator.)
+	*/
+	virtual void Print( FILE* cfile, int depth ) const = 0;
+
+	/**	The world does not agree on whether white space should be kept or
+		not. In order to make everyone happy, these global, static functions
+		are provided to set whether or not TinyXml will condense all white space
+		into a single space or not. The default is to condense. Note changing this
+		value is not thread safe.
+	*/
+	static void SetCondenseWhiteSpace( bool condense )		{ condenseWhiteSpace = condense; }
+
+	/// Return the current white space setting.
+	static bool IsWhiteSpaceCondensed()						{ return condenseWhiteSpace; }
+
+	/** Return the position, in the original source file, of this node or attribute.
+		The row and column are 1-based. (That is the first row and first column is
+		1,1). If the returns values are 0 or less, then the parser does not have
+		a row and column value.
+
+		Generally, the row and column value will be set when the TiXmlDocument::Load(),
+		TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set
+		when the DOM was created from operator>>.
+
+		The values reflect the initial load. Once the DOM is modified programmatically
+		(by adding or changing nodes and attributes) the new values will NOT update to
+		reflect changes in the document.
+
+		There is a minor performance cost to computing the row and column. Computation
+		can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value.
+
+		@sa TiXmlDocument::SetTabSize()
+	*/
+	int Row() const			{ return location.row + 1; }
+	int Column() const		{ return location.col + 1; }	///< See Row()
+
+	void  SetUserData( void* user )			{ userData = user; }	///< Set a pointer to arbitrary user data.
+	void* GetUserData()						{ return userData; }	///< Get a pointer to arbitrary user data.
+	const void* GetUserData() const 		{ return userData; }	///< Get a pointer to arbitrary user data.
+
+	// Table that returs, for a given lead byte, the total number of bytes
+	// in the UTF-8 sequence.
+	static const int utf8ByteTable[256];
+
+	virtual const char* Parse(	const char* p, 
+								TiXmlParsingData* data, 
+								TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0;
+
+	/** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, 
+		or they will be transformed into entities!
+	*/
+	static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out );
+
+	enum
+	{
+		TIXML_NO_ERROR = 0,
+		TIXML_ERROR,
+		TIXML_ERROR_OPENING_FILE,
+		TIXML_ERROR_PARSING_ELEMENT,
+		TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME,
+		TIXML_ERROR_READING_ELEMENT_VALUE,
+		TIXML_ERROR_READING_ATTRIBUTES,
+		TIXML_ERROR_PARSING_EMPTY,
+		TIXML_ERROR_READING_END_TAG,
+		TIXML_ERROR_PARSING_UNKNOWN,
+		TIXML_ERROR_PARSING_COMMENT,
+		TIXML_ERROR_PARSING_DECLARATION,
+		TIXML_ERROR_DOCUMENT_EMPTY,
+		TIXML_ERROR_EMBEDDED_NULL,
+		TIXML_ERROR_PARSING_CDATA,
+		TIXML_ERROR_DOCUMENT_TOP_ONLY,
+
+		TIXML_ERROR_STRING_COUNT
+	};
+
+protected:
+
+	static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding );
+
+	inline static bool IsWhiteSpace( char c )		
+	{ 
+		return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); 
+	}
+	inline static bool IsWhiteSpace( int c )
+	{
+		if ( c < 256 )
+			return IsWhiteSpace( (char) c );
+		return false;	// Again, only truly correct for English/Latin...but usually works.
+	}
+
+	#ifdef TIXML_USE_STL
+	static bool	StreamWhiteSpace( std::istream * in, TIXML_STRING * tag );
+	static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag );
+	#endif
+
+	/*	Reads an XML name into the string provided. Returns
+		a pointer just past the last character of the name,
+		or 0 if the function has an error.
+	*/
+	static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding );
+
+	/*	Reads text. Returns a pointer past the given end tag.
+		Wickedly complex options, but it keeps the (sensitive) code in one place.
+	*/
+	static const char* ReadText(	const char* in,				// where to start
+									TIXML_STRING* text,			// the string read
+									bool ignoreWhiteSpace,		// whether to keep the white space
+									const char* endTag,			// what ends this text
+									bool ignoreCase,			// whether to ignore case in the end tag
+									TiXmlEncoding encoding );	// the current encoding
+
+	// If an entity has been found, transform it into a character.
+	static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding );
+
+	// Get a character, while interpreting entities.
+	// The length can be from 0 to 4 bytes.
+	inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding )
+	{
+		assert( p );
+		if ( encoding == TIXML_ENCODING_UTF8 )
+		{
+			*length = utf8ByteTable[ *((const unsigned char*)p) ];
+			assert( *length >= 0 && *length < 5 );
+		}
+		else
+		{
+			*length = 1;
+		}
+
+		if ( *length == 1 )
+		{
+			if ( *p == '&' )
+				return GetEntity( p, _value, length, encoding );
+			*_value = *p;
+			return p+1;
+		}
+		else if ( *length )
+		{
+			//strncpy( _value, p, *length );	// lots of compilers don't like this function (unsafe),
+												// and the null terminator isn't needed
+			for( int i=0; p[i] && i<*length; ++i ) {
+				_value[i] = p[i];
+			}
+			return p + (*length);
+		}
+		else
+		{
+			// Not valid text.
+			return 0;
+		}
+	}
+
+	// Return true if the next characters in the stream are any of the endTag sequences.
+	// Ignore case only works for english, and should only be relied on when comparing
+	// to English words: StringEqual( p, "version", true ) is fine.
+	static bool StringEqual(	const char* p,
+								const char* endTag,
+								bool ignoreCase,
+								TiXmlEncoding encoding );
+
+	static const char* errorString[ TIXML_ERROR_STRING_COUNT ];
+
+	TiXmlCursor location;
+
+    /// Field containing a generic user pointer
+	void*			userData;
+	
+	// None of these methods are reliable for any language except English.
+	// Good for approximation, not great for accuracy.
+	static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding );
+	static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding );
+	inline static int ToLower( int v, TiXmlEncoding encoding )
+	{
+		if ( encoding == TIXML_ENCODING_UTF8 )
+		{
+			if ( v < 128 ) return tolower( v );
+			return v;
+		}
+		else
+		{
+			return tolower( v );
+		}
+	}
+	static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
+
+private:
+	TiXmlBase( const TiXmlBase& );				// not implemented.
+	void operator=( const TiXmlBase& base );	// not allowed.
+
+	struct Entity
+	{
+		const char*     str;
+		unsigned int	strLength;
+		char		    chr;
+	};
+	enum
+	{
+		NUM_ENTITY = 5,
+		MAX_ENTITY_LENGTH = 6
+
+	};
+	static Entity entity[ NUM_ENTITY ];
+	static bool condenseWhiteSpace;
+};
+
+
+/** The parent class for everything in the Document Object Model.
+	(Except for attributes).
+	Nodes have siblings, a parent, and children. A node can be
+	in a document, or stand on its own. The type of a TiXmlNode
+	can be queried, and it can be cast to its more defined type.
+*/
+class TiXmlNode : public TiXmlBase
+{
+	friend class TiXmlDocument;
+	friend class TiXmlElement;
+
+public:
+	#ifdef TIXML_USE_STL	
+
+	    /** An input stream operator, for every class. Tolerant of newlines and
+		    formatting, but doesn't expect them.
+	    */
+	    friend std::istream& operator >> (std::istream& in, TiXmlNode& base);
+
+	    /** An output stream operator, for every class. Note that this outputs
+		    without any newlines or formatting, as opposed to Print(), which
+		    includes tabs and new lines.
+
+		    The operator<< and operator>> are not completely symmetric. Writing
+		    a node to a stream is very well defined. You'll get a nice stream
+		    of output, without any extra whitespace or newlines.
+		    
+		    But reading is not as well defined. (As it always is.) If you create
+		    a TiXmlElement (for example) and read that from an input stream,
+		    the text needs to define an element or junk will result. This is
+		    true of all input streams, but it's worth keeping in mind.
+
+		    A TiXmlDocument will read nodes until it reads a root element, and
+			all the children of that root element.
+	    */	
+	    friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base);
+
+		/// Appends the XML node or attribute to a std::string.
+		friend std::string& operator<< (std::string& out, const TiXmlNode& base );
+
+	#endif
+
+	/** The types of XML nodes supported by TinyXml. (All the
+			unsupported types are picked up by UNKNOWN.)
+	*/
+	enum NodeType
+	{
+		TINYXML_DOCUMENT,
+		TINYXML_ELEMENT,
+		TINYXML_COMMENT,
+		TINYXML_UNKNOWN,
+		TINYXML_TEXT,
+		TINYXML_DECLARATION,
+		TINYXML_TYPECOUNT
+	};
+
+	virtual ~TiXmlNode();
+
+	/** The meaning of 'value' changes for the specific type of
+		TiXmlNode.
+		@verbatim
+		Document:	filename of the xml file
+		Element:	name of the element
+		Comment:	the comment text
+		Unknown:	the tag contents
+		Text:		the text string
+		@endverbatim
+
+		The subclasses will wrap this function.
+	*/
+	const char *Value() const { return value.c_str (); }
+
+    #ifdef TIXML_USE_STL
+	/** Return Value() as a std::string. If you only use STL,
+	    this is more efficient than calling Value().
+		Only available in STL mode.
+	*/
+	const std::string& ValueStr() const { return value; }
+	#endif
+
+	const TIXML_STRING& ValueTStr() const { return value; }
+
+	/** Changes the value of the node. Defined as:
+		@verbatim
+		Document:	filename of the xml file
+		Element:	name of the element
+		Comment:	the comment text
+		Unknown:	the tag contents
+		Text:		the text string
+		@endverbatim
+	*/
+	void SetValue(const char * _value) { value = _value;}
+
+    #ifdef TIXML_USE_STL
+	/// STL std::string form.
+	void SetValue( const std::string& _value )	{ value = _value; }
+	#endif
+
+	/// Delete all the children of this node. Does not affect 'this'.
+	void Clear();
+
+	/// One step up the DOM.
+	TiXmlNode* Parent()							{ return parent; }
+	const TiXmlNode* Parent() const				{ return parent; }
+
+	const TiXmlNode* FirstChild()	const		{ return firstChild; }	///< The first child of this node. Will be null if there are no children.
+	TiXmlNode* FirstChild()						{ return firstChild; }
+	const TiXmlNode* FirstChild( const char * value ) const;			///< The first child of this node with the matching 'value'. Will be null if none found.
+	/// The first child of this node with the matching 'value'. Will be null if none found.
+	TiXmlNode* FirstChild( const char * _value ) {
+		// Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe)
+		// call the method, cast the return back to non-const.
+		return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value ));
+	}
+	const TiXmlNode* LastChild() const	{ return lastChild; }		/// The last child of this node. Will be null if there are no children.
+	TiXmlNode* LastChild()	{ return lastChild; }
+	
+	const TiXmlNode* LastChild( const char * value ) const;			/// The last child of this node matching 'value'. Will be null if there are no children.
+	TiXmlNode* LastChild( const char * _value ) {
+		return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value ));
+	}
+
+    #ifdef TIXML_USE_STL
+	const TiXmlNode* FirstChild( const std::string& _value ) const	{	return FirstChild (_value.c_str ());	}	///< STL std::string form.
+	TiXmlNode* FirstChild( const std::string& _value )				{	return FirstChild (_value.c_str ());	}	///< STL std::string form.
+	const TiXmlNode* LastChild( const std::string& _value ) const	{	return LastChild (_value.c_str ());	}	///< STL std::string form.
+	TiXmlNode* LastChild( const std::string& _value )				{	return LastChild (_value.c_str ());	}	///< STL std::string form.
+	#endif
+
+	/** An alternate way to walk the children of a node.
+		One way to iterate over nodes is:
+		@verbatim
+			for( child = parent->FirstChild(); child; child = child->NextSibling() )
+		@endverbatim
+
+		IterateChildren does the same thing with the syntax:
+		@verbatim
+			child = 0;
+			while( child = parent->IterateChildren( child ) )
+		@endverbatim
+
+		IterateChildren takes the previous child as input and finds
+		the next one. If the previous child is null, it returns the
+		first. IterateChildren will return null when done.
+	*/
+	const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const;
+	TiXmlNode* IterateChildren( const TiXmlNode* previous ) {
+		return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) );
+	}
+
+	/// This flavor of IterateChildren searches for children with a particular 'value'
+	const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const;
+	TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) {
+		return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) );
+	}
+
+    #ifdef TIXML_USE_STL
+	const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const	{	return IterateChildren (_value.c_str (), previous);	}	///< STL std::string form.
+	TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) {	return IterateChildren (_value.c_str (), previous);	}	///< STL std::string form.
+	#endif
+
+	/** Add a new node related to this. Adds a child past the LastChild.
+		Returns a pointer to the new object or NULL if an error occured.
+	*/
+	TiXmlNode* InsertEndChild( const TiXmlNode& addThis );
+
+
+	/** Add a new node related to this. Adds a child past the LastChild.
+
+		NOTE: the node to be added is passed by pointer, and will be
+		henceforth owned (and deleted) by tinyXml. This method is efficient
+		and avoids an extra copy, but should be used with care as it
+		uses a different memory model than the other insert functions.
+
+		@sa InsertEndChild
+	*/
+	TiXmlNode* LinkEndChild( TiXmlNode* addThis );
+
+	/** Add a new node related to this. Adds a child before the specified child.
+		Returns a pointer to the new object or NULL if an error occured.
+	*/
+	TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis );
+
+	/** Add a new node related to this. Adds a child after the specified child.
+		Returns a pointer to the new object or NULL if an error occured.
+	*/
+	TiXmlNode* InsertAfterChild(  TiXmlNode* afterThis, const TiXmlNode& addThis );
+
+	/** Replace a child of this node.
+		Returns a pointer to the new object or NULL if an error occured.
+	*/
+	TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis );
+
+	/// Delete a child of this node.
+	bool RemoveChild( TiXmlNode* removeThis );
+
+	/// Navigate to a sibling node.
+	const TiXmlNode* PreviousSibling() const			{ return prev; }
+	TiXmlNode* PreviousSibling()						{ return prev; }
+
+	/// Navigate to a sibling node.
+	const TiXmlNode* PreviousSibling( const char * ) const;
+	TiXmlNode* PreviousSibling( const char *_prev ) {
+		return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) );
+	}
+
+    #ifdef TIXML_USE_STL
+	const TiXmlNode* PreviousSibling( const std::string& _value ) const	{	return PreviousSibling (_value.c_str ());	}	///< STL std::string form.
+	TiXmlNode* PreviousSibling( const std::string& _value ) 			{	return PreviousSibling (_value.c_str ());	}	///< STL std::string form.
+	const TiXmlNode* NextSibling( const std::string& _value) const		{	return NextSibling (_value.c_str ());	}	///< STL std::string form.
+	TiXmlNode* NextSibling( const std::string& _value) 					{	return NextSibling (_value.c_str ());	}	///< STL std::string form.
+	#endif
+
+	/// Navigate to a sibling node.
+	const TiXmlNode* NextSibling() const				{ return next; }
+	TiXmlNode* NextSibling()							{ return next; }
+
+	/// Navigate to a sibling node with the given 'value'.
+	const TiXmlNode* NextSibling( const char * ) const;
+	TiXmlNode* NextSibling( const char* _next ) {
+		return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) );
+	}
+
+	/** Convenience function to get through elements.
+		Calls NextSibling and ToElement. Will skip all non-Element
+		nodes. Returns 0 if there is not another element.
+	*/
+	const TiXmlElement* NextSiblingElement() const;
+	TiXmlElement* NextSiblingElement() {
+		return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() );
+	}
+
+	/** Convenience function to get through elements.
+		Calls NextSibling and ToElement. Will skip all non-Element
+		nodes. Returns 0 if there is not another element.
+	*/
+	const TiXmlElement* NextSiblingElement( const char * ) const;
+	TiXmlElement* NextSiblingElement( const char *_next ) {
+		return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) );
+	}
+
+    #ifdef TIXML_USE_STL
+	const TiXmlElement* NextSiblingElement( const std::string& _value) const	{	return NextSiblingElement (_value.c_str ());	}	///< STL std::string form.
+	TiXmlElement* NextSiblingElement( const std::string& _value)				{	return NextSiblingElement (_value.c_str ());	}	///< STL std::string form.
+	#endif
+
+	/// Convenience function to get through elements.
+	const TiXmlElement* FirstChildElement()	const;
+	TiXmlElement* FirstChildElement() {
+		return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() );
+	}
+
+	/// Convenience function to get through elements.
+	const TiXmlElement* FirstChildElement( const char * _value ) const;
+	TiXmlElement* FirstChildElement( const char * _value ) {
+		return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) );
+	}
+
+    #ifdef TIXML_USE_STL
+	const TiXmlElement* FirstChildElement( const std::string& _value ) const	{	return FirstChildElement (_value.c_str ());	}	///< STL std::string form.
+	TiXmlElement* FirstChildElement( const std::string& _value )				{	return FirstChildElement (_value.c_str ());	}	///< STL std::string form.
+	#endif
+
+	/** Query the type (as an enumerated value, above) of this node.
+		The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT,
+								TINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION.
+	*/
+	int Type() const	{ return type; }
+
+	/** Return a pointer to the Document this node lives in.
+		Returns null if not in a document.
+	*/
+	const TiXmlDocument* GetDocument() const;
+	TiXmlDocument* GetDocument() {
+		return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() );
+	}
+
+	/// Returns true if this node has no children.
+	bool NoChildren() const						{ return !firstChild; }
+
+	virtual const TiXmlDocument*    ToDocument()    const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual const TiXmlElement*     ToElement()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual const TiXmlComment*     ToComment()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual const TiXmlUnknown*     ToUnknown()     const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual const TiXmlText*        ToText()        const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+
+	virtual TiXmlDocument*          ToDocument()    { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual TiXmlElement*           ToElement()	    { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual TiXmlComment*           ToComment()     { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual TiXmlUnknown*           ToUnknown()	    { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual TiXmlText*	            ToText()        { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+	virtual TiXmlDeclaration*       ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
+
+	/** Create an exact duplicate of this node and return it. The memory must be deleted
+		by the caller. 
+	*/
+	virtual TiXmlNode* Clone() const = 0;
+
+	/** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the 
+		XML tree will be conditionally visited and the host will be called back
+		via the TiXmlVisitor interface.
+
+		This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
+		the XML for the callbacks, so the performance of TinyXML is unchanged by using this
+		interface versus any other.)
+
+		The interface has been based on ideas from:
+
+		- http://www.saxproject.org/
+		- http://c2.com/cgi/wiki?HierarchicalVisitorPattern 
+
+		Which are both good references for "visiting".
+
+		An example of using Accept():
+		@verbatim
+		TiXmlPrinter printer;
+		tinyxmlDoc.Accept( &printer );
+		const char* xmlcstr = printer.CStr();
+		@endverbatim
+	*/
+	virtual bool Accept( TiXmlVisitor* visitor ) const = 0;
+
+protected:
+	TiXmlNode( NodeType _type );
+
+	// Copy to the allocated object. Shared functionality between Clone, Copy constructor,
+	// and the assignment operator.
+	void CopyTo( TiXmlNode* target ) const;
+
+	#ifdef TIXML_USE_STL
+	    // The real work of the input operator.
+	virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0;
+	#endif
+
+	// Figure out what is at *p, and parse it. Returns null if it is not an xml node.
+	TiXmlNode* Identify( const char* start, TiXmlEncoding encoding );
+
+	TiXmlNode*		parent;
+	NodeType		type;
+
+	TiXmlNode*		firstChild;
+	TiXmlNode*		lastChild;
+
+	TIXML_STRING	value;
+
+	TiXmlNode*		prev;
+	TiXmlNode*		next;
+
+private:
+	TiXmlNode( const TiXmlNode& );				// not implemented.
+	void operator=( const TiXmlNode& base );	// not allowed.
+};
+
+
+/** An attribute is a name-value pair. Elements have an arbitrary
+	number of attributes, each with a unique name.
+
+	@note The attributes are not TiXmlNodes, since they are not
+		  part of the tinyXML document object model. There are other
+		  suggested ways to look at this problem.
+*/
+class TiXmlAttribute : public TiXmlBase
+{
+	friend class TiXmlAttributeSet;
+
+public:
+	/// Construct an empty attribute.
+	TiXmlAttribute() : TiXmlBase()
+	{
+		document = 0;
+		prev = next = 0;
+	}
+
+	#ifdef TIXML_USE_STL
+	/// std::string constructor.
+	TiXmlAttribute( const std::string& _name, const std::string& _value )
+	{
+		name = _name;
+		value = _value;
+		document = 0;
+		prev = next = 0;
+	}
+	#endif
+
+	/// Construct an attribute with a name and value.
+	TiXmlAttribute( const char * _name, const char * _value )
+	{
+		name = _name;
+		value = _value;
+		document = 0;
+		prev = next = 0;
+	}
+
+	const char*		Name()  const		{ return name.c_str(); }		///< Return the name of this attribute.
+	const char*		Value() const		{ return value.c_str(); }		///< Return the value of this attribute.
+	#ifdef TIXML_USE_STL
+	const std::string& ValueStr() const	{ return value; }				///< Return the value of this attribute.
+	#endif
+	int				IntValue() const;									///< Return the value of this attribute, converted to an integer.
+	double			DoubleValue() const;								///< Return the value of this attribute, converted to a double.
+
+	// Get the tinyxml string representation
+	const TIXML_STRING& NameTStr() const { return name; }
+
+	/** QueryIntValue examines the value string. It is an alternative to the
+		IntValue() method with richer error checking.
+		If the value is an integer, it is stored in 'value' and 
+		the call returns TIXML_SUCCESS. If it is not
+		an integer, it returns TIXML_WRONG_TYPE.
+
+		A specialized but useful call. Note that for success it returns 0,
+		which is the opposite of almost all other TinyXml calls.
+	*/
+	int QueryIntValue( int* _value ) const;
+	/// QueryDoubleValue examines the value string. See QueryIntValue().
+	int QueryDoubleValue( double* _value ) const;
+
+	void SetName( const char* _name )	{ name = _name; }				///< Set the name of this attribute.
+	void SetValue( const char* _value )	{ value = _value; }				///< Set the value.
+
+	void SetIntValue( int _value );										///< Set the value from an integer.
+	void SetDoubleValue( double _value );								///< Set the value from a double.
+
+    #ifdef TIXML_USE_STL
+	/// STL std::string form.
+	void SetName( const std::string& _name )	{ name = _name; }	
+	/// STL std::string form.	
+	void SetValue( const std::string& _value )	{ value = _value; }
+	#endif
+
+	/// Get the next sibling attribute in the DOM. Returns null at end.
+	const TiXmlAttribute* Next() const;
+	TiXmlAttribute* Next() {
+		return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); 
+	}
+
+	/// Get the previous sibling attribute in the DOM. Returns null at beginning.
+	const TiXmlAttribute* Previous() const;
+	TiXmlAttribute* Previous() {
+		return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); 
+	}
+
+	bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; }
+	bool operator<( const TiXmlAttribute& rhs )	 const { return name < rhs.name; }
+	bool operator>( const TiXmlAttribute& rhs )  const { return name > rhs.name; }
+
+	/*	Attribute parsing starts: first letter of the name
+						 returns: the next char after the value end quote
+	*/
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	// Prints this Attribute to a FILE stream.
+	virtual void Print( FILE* cfile, int depth ) const {
+		Print( cfile, depth, 0 );
+	}
+	void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
+
+	// [internal use]
+	// Set the document pointer so the attribute can report errors.
+	void SetDocument( TiXmlDocument* doc )	{ document = doc; }
+
+private:
+	TiXmlAttribute( const TiXmlAttribute& );				// not implemented.
+	void operator=( const TiXmlAttribute& base );	// not allowed.
+
+	TiXmlDocument*	document;	// A pointer back to a document, for error reporting.
+	TIXML_STRING name;
+	TIXML_STRING value;
+	TiXmlAttribute*	prev;
+	TiXmlAttribute*	next;
+};
+
+
+/*	A class used to manage a group of attributes.
+	It is only used internally, both by the ELEMENT and the DECLARATION.
+	
+	The set can be changed transparent to the Element and Declaration
+	classes that use it, but NOT transparent to the Attribute
+	which has to implement a next() and previous() method. Which makes
+	it a bit problematic and prevents the use of STL.
+
+	This version is implemented with circular lists because:
+		- I like circular lists
+		- it demonstrates some independence from the (typical) doubly linked list.
+*/
+class TiXmlAttributeSet
+{
+public:
+	TiXmlAttributeSet();
+	~TiXmlAttributeSet();
+
+	void Add( TiXmlAttribute* attribute );
+	void Remove( TiXmlAttribute* attribute );
+
+	const TiXmlAttribute* First()	const	{ return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
+	TiXmlAttribute* First()					{ return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
+	const TiXmlAttribute* Last() const		{ return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
+	TiXmlAttribute* Last()					{ return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
+
+	TiXmlAttribute*	Find( const char* _name ) const;
+	TiXmlAttribute* FindOrCreate( const char* _name );
+
+#	ifdef TIXML_USE_STL
+	TiXmlAttribute*	Find( const std::string& _name ) const;
+	TiXmlAttribute* FindOrCreate( const std::string& _name );
+#	endif
+
+
+private:
+	//*ME:	Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element),
+	//*ME:	this class must be also use a hidden/disabled copy-constructor !!!
+	TiXmlAttributeSet( const TiXmlAttributeSet& );	// not allowed
+	void operator=( const TiXmlAttributeSet& );	// not allowed (as TiXmlAttribute)
+
+	TiXmlAttribute sentinel;
+};
+
+
+/** The element is a container class. It has a value, the element name,
+	and can contain other elements, text, comments, and unknowns.
+	Elements also contain an arbitrary number of attributes.
+*/
+class TiXmlElement : public TiXmlNode
+{
+public:
+	/// Construct an element.
+	TiXmlElement (const char * in_value);
+
+	#ifdef TIXML_USE_STL
+	/// std::string constructor.
+	TiXmlElement( const std::string& _value );
+	#endif
+
+	TiXmlElement( const TiXmlElement& );
+
+	TiXmlElement& operator=( const TiXmlElement& base );
+
+	virtual ~TiXmlElement();
+
+	/** Given an attribute name, Attribute() returns the value
+		for the attribute of that name, or null if none exists.
+	*/
+	const char* Attribute( const char* name ) const;
+
+	/** Given an attribute name, Attribute() returns the value
+		for the attribute of that name, or null if none exists.
+		If the attribute exists and can be converted to an integer,
+		the integer value will be put in the return 'i', if 'i'
+		is non-null.
+	*/
+	const char* Attribute( const char* name, int* i ) const;
+
+	/** Given an attribute name, Attribute() returns the value
+		for the attribute of that name, or null if none exists.
+		If the attribute exists and can be converted to an double,
+		the double value will be put in the return 'd', if 'd'
+		is non-null.
+	*/
+	const char* Attribute( const char* name, double* d ) const;
+
+	/** QueryIntAttribute examines the attribute - it is an alternative to the
+		Attribute() method with richer error checking.
+		If the attribute is an integer, it is stored in 'value' and 
+		the call returns TIXML_SUCCESS. If it is not
+		an integer, it returns TIXML_WRONG_TYPE. If the attribute
+		does not exist, then TIXML_NO_ATTRIBUTE is returned.
+	*/	
+	int QueryIntAttribute( const char* name, int* _value ) const;
+	/// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute().
+	int QueryUnsignedAttribute( const char* name, unsigned* _value ) const;
+	/** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). 
+		Note that '1', 'true', or 'yes' are considered true, while '0', 'false'
+		and 'no' are considered false.
+	*/
+	int QueryBoolAttribute( const char* name, bool* _value ) const;
+	/// QueryDoubleAttribute examines the attribute - see QueryIntAttribute().
+	int QueryDoubleAttribute( const char* name, double* _value ) const;
+	/// QueryFloatAttribute examines the attribute - see QueryIntAttribute().
+	int QueryFloatAttribute( const char* name, float* _value ) const {
+		double d;
+		int result = QueryDoubleAttribute( name, &d );
+		if ( result == TIXML_SUCCESS ) {
+			*_value = (float)d;
+		}
+		return result;
+	}
+
+    #ifdef TIXML_USE_STL
+	/// QueryStringAttribute examines the attribute - see QueryIntAttribute().
+	int QueryStringAttribute( const char* name, std::string* _value ) const {
+		const char* cstr = Attribute( name );
+		if ( cstr ) {
+			*_value = std::string( cstr );
+			return TIXML_SUCCESS;
+		}
+		return TIXML_NO_ATTRIBUTE;
+	}
+
+	/** Template form of the attribute query which will try to read the
+		attribute into the specified type. Very easy, very powerful, but
+		be careful to make sure to call this with the correct type.
+		
+		NOTE: This method doesn't work correctly for 'string' types that contain spaces.
+
+		@return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE
+	*/
+	template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const
+	{
+		const TiXmlAttribute* node = attributeSet.Find( name );
+		if ( !node )
+			return TIXML_NO_ATTRIBUTE;
+
+		std::stringstream sstream( node->ValueStr() );
+		sstream >> *outValue;
+		if ( !sstream.fail() )
+			return TIXML_SUCCESS;
+		return TIXML_WRONG_TYPE;
+	}
+
+	int QueryValueAttribute( const std::string& name, std::string* outValue ) const
+	{
+		const TiXmlAttribute* node = attributeSet.Find( name );
+		if ( !node )
+			return TIXML_NO_ATTRIBUTE;
+		*outValue = node->ValueStr();
+		return TIXML_SUCCESS;
+	}
+	#endif
+
+	/** Sets an attribute of name to a given value. The attribute
+		will be created if it does not exist, or changed if it does.
+	*/
+	void SetAttribute( const char* name, const char * _value );
+
+    #ifdef TIXML_USE_STL
+	const std::string* Attribute( const std::string& name ) const;
+	const std::string* Attribute( const std::string& name, int* i ) const;
+	const std::string* Attribute( const std::string& name, double* d ) const;
+	int QueryIntAttribute( const std::string& name, int* _value ) const;
+	int QueryDoubleAttribute( const std::string& name, double* _value ) const;
+
+	/// STL std::string form.
+	void SetAttribute( const std::string& name, const std::string& _value );
+	///< STL std::string form.
+	void SetAttribute( const std::string& name, int _value );
+	///< STL std::string form.
+	void SetDoubleAttribute( const std::string& name, double value );
+	#endif
+
+	/** Sets an attribute of name to a given value. The attribute
+		will be created if it does not exist, or changed if it does.
+	*/
+	void SetAttribute( const char * name, int value );
+
+	/** Sets an attribute of name to a given value. The attribute
+		will be created if it does not exist, or changed if it does.
+	*/
+	void SetDoubleAttribute( const char * name, double value );
+
+	/** Deletes an attribute with the given name.
+	*/
+	void RemoveAttribute( const char * name );
+    #ifdef TIXML_USE_STL
+	void RemoveAttribute( const std::string& name )	{	RemoveAttribute (name.c_str ());	}	///< STL std::string form.
+	#endif
+
+	const TiXmlAttribute* FirstAttribute() const	{ return attributeSet.First(); }		///< Access the first attribute in this element.
+	TiXmlAttribute* FirstAttribute() 				{ return attributeSet.First(); }
+	const TiXmlAttribute* LastAttribute()	const 	{ return attributeSet.Last(); }		///< Access the last attribute in this element.
+	TiXmlAttribute* LastAttribute()					{ return attributeSet.Last(); }
+
+	/** Convenience function for easy access to the text inside an element. Although easy
+		and concise, GetText() is limited compared to getting the TiXmlText child
+		and accessing it directly.
+	
+		If the first child of 'this' is a TiXmlText, the GetText()
+		returns the character string of the Text node, else null is returned.
+
+		This is a convenient method for getting the text of simple contained text:
+		@verbatim
+		<foo>This is text</foo>
+		const char* str = fooElement->GetText();
+		@endverbatim
+
+		'str' will be a pointer to "This is text". 
+		
+		Note that this function can be misleading. If the element foo was created from
+		this XML:
+		@verbatim
+		<foo><b>This is text</b></foo> 
+		@endverbatim
+
+		then the value of str would be null. The first child node isn't a text node, it is
+		another element. From this XML:
+		@verbatim
+		<foo>This is <b>text</b></foo> 
+		@endverbatim
+		GetText() will return "This is ".
+
+		WARNING: GetText() accesses a child node - don't become confused with the 
+				 similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are 
+				 safe type casts on the referenced node.
+	*/
+	const char* GetText() const;
+
+	/// Creates a new Element and returns it - the returned element is a copy.
+	virtual TiXmlNode* Clone() const;
+	// Print the Element to a FILE stream.
+	virtual void Print( FILE* cfile, int depth ) const;
+
+	/*	Attribtue parsing starts: next char past '<'
+						 returns: next char past '>'
+	*/
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	virtual const TiXmlElement*     ToElement()     const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual TiXmlElement*           ToElement()	          { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+
+	void CopyTo( TiXmlElement* target ) const;
+	void ClearThis();	// like clear, but initializes 'this' object as well
+
+	// Used to be public [internal use]
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+	/*	[internal use]
+		Reads the "value" of the element -- another element, or text.
+		This should terminate with the current end tag.
+	*/
+	const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding );
+
+private:
+	TiXmlAttributeSet attributeSet;
+};
+
+
+/**	An XML comment.
+*/
+class TiXmlComment : public TiXmlNode
+{
+public:
+	/// Constructs an empty comment.
+	TiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {}
+	/// Construct a comment from text.
+	TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {
+		SetValue( _value );
+	}
+	TiXmlComment( const TiXmlComment& );
+	TiXmlComment& operator=( const TiXmlComment& base );
+
+	virtual ~TiXmlComment()	{}
+
+	/// Returns a copy of this Comment.
+	virtual TiXmlNode* Clone() const;
+	// Write this Comment to a FILE stream.
+	virtual void Print( FILE* cfile, int depth ) const;
+
+	/*	Attribtue parsing starts: at the ! of the !--
+						 returns: next char past '>'
+	*/
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	virtual const TiXmlComment*  ToComment() const	{ return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual		  TiXmlComment*  ToComment()		{ return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+	void CopyTo( TiXmlComment* target ) const;
+
+	// used to be public
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+//	virtual void StreamOut( TIXML_OSTREAM * out ) const;
+
+private:
+
+};
+
+
+/** XML text. A text node can have 2 ways to output the next. "normal" output 
+	and CDATA. It will default to the mode it was parsed from the XML file and
+	you generally want to leave it alone, but you can change the output mode with 
+	SetCDATA() and query it with CDATA().
+*/
+class TiXmlText : public TiXmlNode
+{
+	friend class TiXmlElement;
+public:
+	/** Constructor for text element. By default, it is treated as 
+		normal, encoded text. If you want it be output as a CDATA text
+		element, set the parameter _cdata to 'true'
+	*/
+	TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT)
+	{
+		SetValue( initValue );
+		cdata = false;
+	}
+	virtual ~TiXmlText() {}
+
+	#ifdef TIXML_USE_STL
+	/// Constructor.
+	TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT)
+	{
+		SetValue( initValue );
+		cdata = false;
+	}
+	#endif
+
+	TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT )	{ copy.CopyTo( this ); }
+	TiXmlText& operator=( const TiXmlText& base )							 	{ base.CopyTo( this ); return *this; }
+
+	// Write this text object to a FILE stream.
+	virtual void Print( FILE* cfile, int depth ) const;
+
+	/// Queries whether this represents text using a CDATA section.
+	bool CDATA() const				{ return cdata; }
+	/// Turns on or off a CDATA representation of text.
+	void SetCDATA( bool _cdata )	{ cdata = _cdata; }
+
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual TiXmlText*       ToText()       { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected :
+	///  [internal use] Creates a new Element and returns it.
+	virtual TiXmlNode* Clone() const;
+	void CopyTo( TiXmlText* target ) const;
+
+	bool Blank() const;	// returns true if all white space and new lines
+	// [internal use]
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+
+private:
+	bool cdata;			// true if this should be input and output as a CDATA style text element
+};
+
+
+/** In correct XML the declaration is the first entry in the file.
+	@verbatim
+		<?xml version="1.0" standalone="yes"?>
+	@endverbatim
+
+	TinyXml will happily read or write files without a declaration,
+	however. There are 3 possible attributes to the declaration:
+	version, encoding, and standalone.
+
+	Note: In this version of the code, the attributes are
+	handled as special cases, not generic attributes, simply
+	because there can only be at most 3 and they are always the same.
+*/
+class TiXmlDeclaration : public TiXmlNode
+{
+public:
+	/// Construct an empty declaration.
+	TiXmlDeclaration()   : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {}
+
+#ifdef TIXML_USE_STL
+	/// Constructor.
+	TiXmlDeclaration(	const std::string& _version,
+						const std::string& _encoding,
+						const std::string& _standalone );
+#endif
+
+	/// Construct.
+	TiXmlDeclaration(	const char* _version,
+						const char* _encoding,
+						const char* _standalone );
+
+	TiXmlDeclaration( const TiXmlDeclaration& copy );
+	TiXmlDeclaration& operator=( const TiXmlDeclaration& copy );
+
+	virtual ~TiXmlDeclaration()	{}
+
+	/// Version. Will return an empty string if none was found.
+	const char *Version() const			{ return version.c_str (); }
+	/// Encoding. Will return an empty string if none was found.
+	const char *Encoding() const		{ return encoding.c_str (); }
+	/// Is this a standalone document?
+	const char *Standalone() const		{ return standalone.c_str (); }
+
+	/// Creates a copy of this Declaration and returns it.
+	virtual TiXmlNode* Clone() const;
+	// Print this declaration to a FILE stream.
+	virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
+	virtual void Print( FILE* cfile, int depth ) const {
+		Print( cfile, depth, 0 );
+	}
+
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual TiXmlDeclaration*       ToDeclaration()       { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* visitor ) const;
+
+protected:
+	void CopyTo( TiXmlDeclaration* target ) const;
+	// used to be public
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+
+private:
+
+	TIXML_STRING version;
+	TIXML_STRING encoding;
+	TIXML_STRING standalone;
+};
+
+
+/** Any tag that tinyXml doesn't recognize is saved as an
+	unknown. It is a tag of text, but should not be modified.
+	It will be written back to the XML, unchanged, when the file
+	is saved.
+
+	DTD tags get thrown into TiXmlUnknowns.
+*/
+class TiXmlUnknown : public TiXmlNode
+{
+public:
+	TiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN )	{}
+	virtual ~TiXmlUnknown() {}
+
+	TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN )		{ copy.CopyTo( this ); }
+	TiXmlUnknown& operator=( const TiXmlUnknown& copy )										{ copy.CopyTo( this ); return *this; }
+
+	/// Creates a copy of this Unknown and returns it.
+	virtual TiXmlNode* Clone() const;
+	// Print this Unknown to a FILE stream.
+	virtual void Print( FILE* cfile, int depth ) const;
+
+	virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
+
+	virtual const TiXmlUnknown*     ToUnknown()     const	{ return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual TiXmlUnknown*           ToUnknown()				{ return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected:
+	void CopyTo( TiXmlUnknown* target ) const;
+
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+
+private:
+
+};
+
+
+/** Always the top level node. A document binds together all the
+	XML pieces. It can be saved, loaded, and printed to the screen.
+	The 'value' of a document node is the xml file name.
+*/
+class TiXmlDocument : public TiXmlNode
+{
+public:
+	/// Create an empty document, that has no name.
+	TiXmlDocument();
+	/// Create a document with a name. The name of the document is also the filename of the xml.
+	TiXmlDocument( const char * documentName );
+
+	#ifdef TIXML_USE_STL
+	/// Constructor.
+	TiXmlDocument( const std::string& documentName );
+	#endif
+
+	TiXmlDocument( const TiXmlDocument& copy );
+	TiXmlDocument& operator=( const TiXmlDocument& copy );
+
+	virtual ~TiXmlDocument() {}
+
+	/** Load a file using the current document value.
+		Returns true if successful. Will delete any existing
+		document data before loading.
+	*/
+	bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+	/// Save a file using the current document value. Returns true if successful.
+	bool SaveFile() const;
+	/// Load a file using the given filename. Returns true if successful.
+	bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+	/// Save a file using the given filename. Returns true if successful.
+	bool SaveFile( const char * filename ) const;
+	/** Load a file using the given FILE*. Returns true if successful. Note that this method
+		doesn't stream - the entire object pointed at by the FILE*
+		will be interpreted as an XML file. TinyXML doesn't stream in XML from the current
+		file location. Streaming may be added in the future.
+	*/
+	bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+	/// Save a file using the given FILE*. Returns true if successful.
+	bool SaveFile( FILE* ) const;
+
+	#ifdef TIXML_USE_STL
+	bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING )			///< STL std::string version.
+	{
+		return LoadFile( filename.c_str(), encoding );
+	}
+	bool SaveFile( const std::string& filename ) const		///< STL std::string version.
+	{
+		return SaveFile( filename.c_str() );
+	}
+	#endif
+
+	/** Parse the given null terminated block of xml data. Passing in an encoding to this
+		method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml
+		to use that encoding, regardless of what TinyXml might otherwise try to detect.
+	*/
+	virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
+
+	/** Get the root element -- the only top level element -- of the document.
+		In well formed XML, there should only be one. TinyXml is tolerant of
+		multiple elements at the document level.
+	*/
+	const TiXmlElement* RootElement() const		{ return FirstChildElement(); }
+	TiXmlElement* RootElement()					{ return FirstChildElement(); }
+
+	/** If an error occurs, Error will be set to true. Also,
+		- The ErrorId() will contain the integer identifier of the error (not generally useful)
+		- The ErrorDesc() method will return the name of the error. (very useful)
+		- The ErrorRow() and ErrorCol() will return the location of the error (if known)
+	*/	
+	bool Error() const						{ return error; }
+
+	/// Contains a textual (english) description of the error if one occurs.
+	const char * ErrorDesc() const	{ return errorDesc.c_str (); }
+
+	/** Generally, you probably want the error string ( ErrorDesc() ). But if you
+		prefer the ErrorId, this function will fetch it.
+	*/
+	int ErrorId()	const				{ return errorId; }
+
+	/** Returns the location (if known) of the error. The first column is column 1, 
+		and the first row is row 1. A value of 0 means the row and column wasn't applicable
+		(memory errors, for example, have no row/column) or the parser lost the error. (An
+		error in the error reporting, in that case.)
+
+		@sa SetTabSize, Row, Column
+	*/
+	int ErrorRow() const	{ return errorLocation.row+1; }
+	int ErrorCol() const	{ return errorLocation.col+1; }	///< The column where the error occured. See ErrorRow()
+
+	/** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol())
+		to report the correct values for row and column. It does not change the output
+		or input in any way.
+		
+		By calling this method, with a tab size
+		greater than 0, the row and column of each node and attribute is stored
+		when the file is loaded. Very useful for tracking the DOM back in to
+		the source file.
+
+		The tab size is required for calculating the location of nodes. If not
+		set, the default of 4 is used. The tabsize is set per document. Setting
+		the tabsize to 0 disables row/column tracking.
+
+		Note that row and column tracking is not supported when using operator>>.
+
+		The tab size needs to be enabled before the parse or load. Correct usage:
+		@verbatim
+		TiXmlDocument doc;
+		doc.SetTabSize( 8 );
+		doc.Load( "myfile.xml" );
+		@endverbatim
+
+		@sa Row, Column
+	*/
+	void SetTabSize( int _tabsize )		{ tabsize = _tabsize; }
+
+	int TabSize() const	{ return tabsize; }
+
+	/** If you have handled the error, it can be reset with this call. The error
+		state is automatically cleared if you Parse a new XML block.
+	*/
+	void ClearError()						{	error = false; 
+												errorId = 0; 
+												errorDesc = ""; 
+												errorLocation.row = errorLocation.col = 0; 
+												//errorLocation.last = 0; 
+											}
+
+	/** Write the document to standard out using formatted printing ("pretty print"). */
+	void Print() const						{ Print( stdout, 0 ); }
+
+	/* Write the document to a string using formatted printing ("pretty print"). This
+		will allocate a character array (new char[]) and return it as a pointer. The
+		calling code pust call delete[] on the return char* to avoid a memory leak.
+	*/
+	//char* PrintToMemory() const; 
+
+	/// Print this Document to a FILE stream.
+	virtual void Print( FILE* cfile, int depth = 0 ) const;
+	// [internal use]
+	void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding );
+
+	virtual const TiXmlDocument*    ToDocument()    const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+	virtual TiXmlDocument*          ToDocument()          { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
+
+	/** Walk the XML tree visiting this node and all of its children. 
+	*/
+	virtual bool Accept( TiXmlVisitor* content ) const;
+
+protected :
+	// [internal use]
+	virtual TiXmlNode* Clone() const;
+	#ifdef TIXML_USE_STL
+	virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
+	#endif
+
+private:
+	void CopyTo( TiXmlDocument* target ) const;
+
+	bool error;
+	int  errorId;
+	TIXML_STRING errorDesc;
+	int tabsize;
+	TiXmlCursor errorLocation;
+	bool useMicrosoftBOM;		// the UTF-8 BOM were found when read. Note this, and try to write.
+};
+
+
+/**
+	A TiXmlHandle is a class that wraps a node pointer with null checks; this is
+	an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml
+	DOM structure. It is a separate utility class.
+
+	Take an example:
+	@verbatim
+	<Document>
+		<Element attributeA = "valueA">
+			<Child attributeB = "value1" />
+			<Child attributeB = "value2" />
+		</Element>
+	<Document>
+	@endverbatim
+
+	Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very 
+	easy to write a *lot* of code that looks like:
+
+	@verbatim
+	TiXmlElement* root = document.FirstChildElement( "Document" );
+	if ( root )
+	{
+		TiXmlElement* element = root->FirstChildElement( "Element" );
+		if ( element )
+		{
+			TiXmlElement* child = element->FirstChildElement( "Child" );
+			if ( child )
+			{
+				TiXmlElement* child2 = child->NextSiblingElement( "Child" );
+				if ( child2 )
+				{
+					// Finally do something useful.
+	@endverbatim
+
+	And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity
+	of such code. A TiXmlHandle checks for null	pointers so it is perfectly safe 
+	and correct to use:
+
+	@verbatim
+	TiXmlHandle docHandle( &document );
+	TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement();
+	if ( child2 )
+	{
+		// do something useful
+	@endverbatim
+
+	Which is MUCH more concise and useful.
+
+	It is also safe to copy handles - internally they are nothing more than node pointers.
+	@verbatim
+	TiXmlHandle handleCopy = handle;
+	@endverbatim
+
+	What they should not be used for is iteration:
+
+	@verbatim
+	int i=0; 
+	while ( true )
+	{
+		TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement();
+		if ( !child )
+			break;
+		// do something
+		++i;
+	}
+	@endverbatim
+
+	It seems reasonable, but it is in fact two embedded while loops. The Child method is 
+	a linear walk to find the element, so this code would iterate much more than it needs 
+	to. Instead, prefer:
+
+	@verbatim
+	TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement();
+
+	for( child; child; child=child->NextSiblingElement() )
+	{
+		// do something
+	}
+	@endverbatim
+*/
+class TiXmlHandle
+{
+public:
+	/// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
+	TiXmlHandle( TiXmlNode* _node )					{ this->node = _node; }
+	/// Copy constructor
+	TiXmlHandle( const TiXmlHandle& ref )			{ this->node = ref.node; }
+	TiXmlHandle operator=( const TiXmlHandle& ref ) { if ( &ref != this ) this->node = ref.node; return *this; }
+
+	/// Return a handle to the first child node.
+	TiXmlHandle FirstChild() const;
+	/// Return a handle to the first child node with the given name.
+	TiXmlHandle FirstChild( const char * value ) const;
+	/// Return a handle to the first child element.
+	TiXmlHandle FirstChildElement() const;
+	/// Return a handle to the first child element with the given name.
+	TiXmlHandle FirstChildElement( const char * value ) const;
+
+	/** Return a handle to the "index" child with the given name. 
+		The first child is 0, the second 1, etc.
+	*/
+	TiXmlHandle Child( const char* value, int index ) const;
+	/** Return a handle to the "index" child. 
+		The first child is 0, the second 1, etc.
+	*/
+	TiXmlHandle Child( int index ) const;
+	/** Return a handle to the "index" child element with the given name. 
+		The first child element is 0, the second 1, etc. Note that only TiXmlElements
+		are indexed: other types are not counted.
+	*/
+	TiXmlHandle ChildElement( const char* value, int index ) const;
+	/** Return a handle to the "index" child element. 
+		The first child element is 0, the second 1, etc. Note that only TiXmlElements
+		are indexed: other types are not counted.
+	*/
+	TiXmlHandle ChildElement( int index ) const;
+
+	#ifdef TIXML_USE_STL
+	TiXmlHandle FirstChild( const std::string& _value ) const				{ return FirstChild( _value.c_str() ); }
+	TiXmlHandle FirstChildElement( const std::string& _value ) const		{ return FirstChildElement( _value.c_str() ); }
+
+	TiXmlHandle Child( const std::string& _value, int index ) const			{ return Child( _value.c_str(), index ); }
+	TiXmlHandle ChildElement( const std::string& _value, int index ) const	{ return ChildElement( _value.c_str(), index ); }
+	#endif
+
+	/** Return the handle as a TiXmlNode. This may return null.
+	*/
+	TiXmlNode* ToNode() const			{ return node; } 
+	/** Return the handle as a TiXmlElement. This may return null.
+	*/
+	TiXmlElement* ToElement() const		{ return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
+	/**	Return the handle as a TiXmlText. This may return null.
+	*/
+	TiXmlText* ToText() const			{ return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
+	/** Return the handle as a TiXmlUnknown. This may return null.
+	*/
+	TiXmlUnknown* ToUnknown() const		{ return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
+
+	/** @deprecated use ToNode. 
+		Return the handle as a TiXmlNode. This may return null.
+	*/
+	TiXmlNode* Node() const			{ return ToNode(); } 
+	/** @deprecated use ToElement. 
+		Return the handle as a TiXmlElement. This may return null.
+	*/
+	TiXmlElement* Element() const	{ return ToElement(); }
+	/**	@deprecated use ToText()
+		Return the handle as a TiXmlText. This may return null.
+	*/
+	TiXmlText* Text() const			{ return ToText(); }
+	/** @deprecated use ToUnknown()
+		Return the handle as a TiXmlUnknown. This may return null.
+	*/
+	TiXmlUnknown* Unknown() const	{ return ToUnknown(); }
+
+private:
+	TiXmlNode* node;
+};
+
+
+/** Print to memory functionality. The TiXmlPrinter is useful when you need to:
+
+	-# Print to memory (especially in non-STL mode)
+	-# Control formatting (line endings, etc.)
+
+	When constructed, the TiXmlPrinter is in its default "pretty printing" mode.
+	Before calling Accept() you can call methods to control the printing
+	of the XML document. After TiXmlNode::Accept() is called, the printed document can
+	be accessed via the CStr(), Str(), and Size() methods.
+
+	TiXmlPrinter uses the Visitor API.
+	@verbatim
+	TiXmlPrinter printer;
+	printer.SetIndent( "\t" );
+
+	doc.Accept( &printer );
+	fprintf( stdout, "%s", printer.CStr() );
+	@endverbatim
+*/
+class TiXmlPrinter : public TiXmlVisitor
+{
+public:
+	TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ),
+					 buffer(), indent( "    " ), lineBreak( "\n" ) {}
+
+	virtual bool VisitEnter( const TiXmlDocument& doc );
+	virtual bool VisitExit( const TiXmlDocument& doc );
+
+	virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute );
+	virtual bool VisitExit( const TiXmlElement& element );
+
+	virtual bool Visit( const TiXmlDeclaration& declaration );
+	virtual bool Visit( const TiXmlText& text );
+	virtual bool Visit( const TiXmlComment& comment );
+	virtual bool Visit( const TiXmlUnknown& unknown );
+
+	/** Set the indent characters for printing. By default 4 spaces
+		but tab (\t) is also useful, or null/empty string for no indentation.
+	*/
+	void SetIndent( const char* _indent )			{ indent = _indent ? _indent : "" ; }
+	/// Query the indention string.
+	const char* Indent()							{ return indent.c_str(); }
+	/** Set the line breaking string. By default set to newline (\n). 
+		Some operating systems prefer other characters, or can be
+		set to the null/empty string for no indenation.
+	*/
+	void SetLineBreak( const char* _lineBreak )		{ lineBreak = _lineBreak ? _lineBreak : ""; }
+	/// Query the current line breaking string.
+	const char* LineBreak()							{ return lineBreak.c_str(); }
+
+	/** Switch over to "stream printing" which is the most dense formatting without 
+		linebreaks. Common when the XML is needed for network transmission.
+	*/
+	void SetStreamPrinting()						{ indent = "";
+													  lineBreak = "";
+													}	
+	/// Return the result.
+	const char* CStr()								{ return buffer.c_str(); }
+	/// Return the length of the result string.
+	size_t Size()									{ return buffer.size(); }
+
+	#ifdef TIXML_USE_STL
+	/// Return the result.
+	const std::string& Str()						{ return buffer; }
+	#endif
+
+private:
+	void DoIndent()	{
+		for( int i=0; i<depth; ++i )
+			buffer += indent;
+	}
+	void DoLineBreak() {
+		buffer += lineBreak;
+	}
+
+	int depth;
+	bool simpleTextPrint;
+	TIXML_STRING buffer;
+	TIXML_STRING indent;
+	TIXML_STRING lineBreak;
+};
+
+
+#ifdef _MSC_VER
+#pragma warning( pop )
+#endif
+
+#endif
diff --git a/cpp/src/test/tinyxml/tinyxmlerror.cpp b/cpp/src/test/tinyxml/tinyxmlerror.cpp
new file mode 100644
index 0000000..538c21d
--- /dev/null
+++ b/cpp/src/test/tinyxml/tinyxmlerror.cpp
@@ -0,0 +1,52 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied 
+warranty. In no event will the authors be held liable for any 
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any 
+purpose, including commercial applications, and to alter it and 
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+distribution.
+*/
+
+#include "tinyxml.h"
+
+// The goal of the seperate error file is to make the first
+// step towards localization. tinyxml (currently) only supports
+// english error messages, but the could now be translated.
+//
+// It also cleans up the code a bit.
+//
+
+const char* TiXmlBase::errorString[ TiXmlBase::TIXML_ERROR_STRING_COUNT ] =
+{
+	"No error",
+	"Error",
+	"Failed to open file",
+	"Error parsing Element.",
+	"Failed to read Element name",
+	"Error reading Element value.",
+	"Error reading Attributes.",
+	"Error: empty tag.",
+	"Error reading end tag.",
+	"Error parsing Unknown.",
+	"Error parsing Comment.",
+	"Error parsing Declaration.",
+	"Error document empty.",
+	"Error null (0) or unexpected EOF found in input stream.",
+	"Error parsing CDATA.",
+	"Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.",
+};
diff --git a/cpp/src/test/tinyxml/tinyxmlparser.cpp b/cpp/src/test/tinyxml/tinyxmlparser.cpp
new file mode 100644
index 0000000..81b7eae
--- /dev/null
+++ b/cpp/src/test/tinyxml/tinyxmlparser.cpp
@@ -0,0 +1,1638 @@
+/*
+www.sourceforge.net/projects/tinyxml
+Original code by Lee Thomason (www.grinninglizard.com)
+
+This software is provided 'as-is', without any express or implied 
+warranty. In no event will the authors be held liable for any 
+damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any 
+purpose, including commercial applications, and to alter it and 
+redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must 
+not claim that you wrote the original software. If you use this
+software in a product, an acknowledgment in the product documentation
+would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and 
+must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source 
+distribution.
+*/
+
+#include <ctype.h>
+#include <stddef.h>
+
+#include "tinyxml.h"
+
+//#define DEBUG_PARSER
+#if defined( DEBUG_PARSER )
+#	if defined( DEBUG ) && defined( _MSC_VER )
+#		include <windows.h>
+#		define TIXML_LOG OutputDebugString
+#	else
+#		define TIXML_LOG printf
+#	endif
+#endif
+
+// Note tha "PutString" hardcodes the same list. This
+// is less flexible than it appears. Changing the entries
+// or order will break putstring.	
+TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = 
+{
+	{ "&amp;",  5, '&' },
+	{ "&lt;",   4, '<' },
+	{ "&gt;",   4, '>' },
+	{ "&quot;", 6, '\"' },
+	{ "&apos;", 6, '\'' }
+};
+
+// Bunch of unicode info at:
+//		http://www.unicode.org/faq/utf_bom.html
+// Including the basic of this table, which determines the #bytes in the
+// sequence from the lead byte. 1 placed for invalid sequences --
+// although the result will be junk, pass it through as much as possible.
+// Beware of the non-characters in UTF-8:	
+//				ef bb bf (Microsoft "lead bytes")
+//				ef bf be
+//				ef bf bf 
+
+const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
+const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
+const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
+
+const int TiXmlBase::utf8ByteTable[256] = 
+{
+	//	0	1	2	3	4	5	6	7	8	9	a	b	c	d	e	f
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0x00
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0x10
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0x20
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0x30
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0x40
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0x50
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0x60
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0x70	End of ASCII range
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0x80 0x80 to 0xc1 invalid
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0x90 
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0xa0 
+		1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	// 0xb0 
+		1,	1,	2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	// 0xc0 0xc2 to 0xdf 2 byte
+		2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	2,	// 0xd0
+		3,	3,	3,	3,	3,	3,	3,	3,	3,	3,	3,	3,	3,	3,	3,	3,	// 0xe0 0xe0 to 0xef 3 byte
+		4,	4,	4,	4,	4,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1,	1	// 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
+};
+
+
+void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
+{
+	const unsigned long BYTE_MASK = 0xBF;
+	const unsigned long BYTE_MARK = 0x80;
+	const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+	if (input < 0x80) 
+		*length = 1;
+	else if ( input < 0x800 )
+		*length = 2;
+	else if ( input < 0x10000 )
+		*length = 3;
+	else if ( input < 0x200000 )
+		*length = 4;
+	else
+		{ *length = 0; return; }	// This code won't covert this correctly anyway.
+
+	output += *length;
+
+	// Scary scary fall throughs.
+	switch (*length) 
+	{
+		case 4:
+			--output; 
+			*output = (char)((input | BYTE_MARK) & BYTE_MASK); 
+			input >>= 6;
+		case 3:
+			--output; 
+			*output = (char)((input | BYTE_MARK) & BYTE_MASK); 
+			input >>= 6;
+		case 2:
+			--output; 
+			*output = (char)((input | BYTE_MARK) & BYTE_MASK); 
+			input >>= 6;
+		case 1:
+			--output; 
+			*output = (char)(input | FIRST_BYTE_MARK[*length]);
+	}
+}
+
+
+/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
+{
+	// This will only work for low-ascii, everything else is assumed to be a valid
+	// letter. I'm not sure this is the best approach, but it is quite tricky trying
+	// to figure out alhabetical vs. not across encoding. So take a very 
+	// conservative approach.
+
+//	if ( encoding == TIXML_ENCODING_UTF8 )
+//	{
+		if ( anyByte < 127 )
+			return isalpha( anyByte );
+		else
+			return 1;	// What else to do? The unicode set is huge...get the english ones right.
+//	}
+//	else
+//	{
+//		return isalpha( anyByte );
+//	}
+}
+
+
+/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
+{
+	// This will only work for low-ascii, everything else is assumed to be a valid
+	// letter. I'm not sure this is the best approach, but it is quite tricky trying
+	// to figure out alhabetical vs. not across encoding. So take a very 
+	// conservative approach.
+
+//	if ( encoding == TIXML_ENCODING_UTF8 )
+//	{
+		if ( anyByte < 127 )
+			return isalnum( anyByte );
+		else
+			return 1;	// What else to do? The unicode set is huge...get the english ones right.
+//	}
+//	else
+//	{
+//		return isalnum( anyByte );
+//	}
+}
+
+
+class TiXmlParsingData
+{
+	friend class TiXmlDocument;
+  public:
+	void Stamp( const char* now, TiXmlEncoding encoding );
+
+	const TiXmlCursor& Cursor() const	{ return cursor; }
+
+  private:
+	// Only used by the document!
+	TiXmlParsingData( const char* start, int _tabsize, int row, int col )
+	{
+		assert( start );
+		stamp = start;
+		tabsize = _tabsize;
+		cursor.row = row;
+		cursor.col = col;
+	}
+
+	TiXmlCursor		cursor;
+	const char*		stamp;
+	int				tabsize;
+};
+
+
+void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )
+{
+	assert( now );
+
+	// Do nothing if the tabsize is 0.
+	if ( tabsize < 1 )
+	{
+		return;
+	}
+
+	// Get the current row, column.
+	int row = cursor.row;
+	int col = cursor.col;
+	const char* p = stamp;
+	assert( p );
+
+	while ( p < now )
+	{
+		// Treat p as unsigned, so we have a happy compiler.
+		const unsigned char* pU = (const unsigned char*)p;
+
+		// Code contributed by Fletcher Dunn: (modified by lee)
+		switch (*pU) {
+			case 0:
+				// We *should* never get here, but in case we do, don't
+				// advance past the terminating null character, ever
+				return;
+
+			case '\r':
+				// bump down to the next line
+				++row;
+				col = 0;				
+				// Eat the character
+				++p;
+
+				// Check for \r\n sequence, and treat this as a single character
+				if (*p == '\n') {
+					++p;
+				}
+				break;
+
+			case '\n':
+				// bump down to the next line
+				++row;
+				col = 0;
+
+				// Eat the character
+				++p;
+
+				// Check for \n\r sequence, and treat this as a single
+				// character.  (Yes, this bizarre thing does occur still
+				// on some arcane platforms...)
+				if (*p == '\r') {
+					++p;
+				}
+				break;
+
+			case '\t':
+				// Eat the character
+				++p;
+
+				// Skip to next tab stop
+				col = (col / tabsize + 1) * tabsize;
+				break;
+
+			case TIXML_UTF_LEAD_0:
+				if ( encoding == TIXML_ENCODING_UTF8 )
+				{
+					if ( *(p+1) && *(p+2) )
+					{
+						// In these cases, don't advance the column. These are
+						// 0-width spaces.
+						if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )
+							p += 3;	
+						else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )
+							p += 3;	
+						else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )
+							p += 3;	
+						else
+							{ p +=3; ++col; }	// A normal character.
+					}
+				}
+				else
+				{
+					++p;
+					++col;
+				}
+				break;
+
+			default:
+				if ( encoding == TIXML_ENCODING_UTF8 )
+				{
+					// Eat the 1 to 4 byte utf8 character.
+					int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)];
+					if ( step == 0 )
+						step = 1;		// Error case from bad encoding, but handle gracefully.
+					p += step;
+
+					// Just advance one column, of course.
+					++col;
+				}
+				else
+				{
+					++p;
+					++col;
+				}
+				break;
+		}
+	}
+	cursor.row = row;
+	cursor.col = col;
+	assert( cursor.row >= -1 );
+	assert( cursor.col >= -1 );
+	stamp = p;
+	assert( stamp );
+}
+
+
+const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )
+{
+	if ( !p || !*p )
+	{
+		return 0;
+	}
+	if ( encoding == TIXML_ENCODING_UTF8 )
+	{
+		while ( *p )
+		{
+			const unsigned char* pU = (const unsigned char*)p;
+			
+			// Skip the stupid Microsoft UTF-8 Byte order marks
+			if (	*(pU+0)==TIXML_UTF_LEAD_0
+				 && *(pU+1)==TIXML_UTF_LEAD_1 
+				 && *(pU+2)==TIXML_UTF_LEAD_2 )
+			{
+				p += 3;
+				continue;
+			}
+			else if(*(pU+0)==TIXML_UTF_LEAD_0
+				 && *(pU+1)==0xbfU
+				 && *(pU+2)==0xbeU )
+			{
+				p += 3;
+				continue;
+			}
+			else if(*(pU+0)==TIXML_UTF_LEAD_0
+				 && *(pU+1)==0xbfU
+				 && *(pU+2)==0xbfU )
+			{
+				p += 3;
+				continue;
+			}
+
+			if ( IsWhiteSpace( *p ) )		// Still using old rules for white space.
+				++p;
+			else
+				break;
+		}
+	}
+	else
+	{
+		while ( *p && IsWhiteSpace( *p ) )
+			++p;
+	}
+
+	return p;
+}
+
+#ifdef TIXML_USE_STL
+/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag )
+{
+	for( ;; )
+	{
+		if ( !in->good() ) return false;
+
+		int c = in->peek();
+		// At this scope, we can't get to a document. So fail silently.
+		if ( !IsWhiteSpace( c ) || c <= 0 )
+			return true;
+
+		*tag += (char) in->get();
+	}
+}
+
+/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag )
+{
+	//assert( character > 0 && character < 128 );	// else it won't work in utf-8
+	while ( in->good() )
+	{
+		int c = in->peek();
+		if ( c == character )
+			return true;
+		if ( c <= 0 )		// Silent failure: can't get document at this scope
+			return false;
+
+		in->get();
+		*tag += (char) c;
+	}
+	return false;
+}
+#endif
+
+// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The
+// "assign" optimization removes over 10% of the execution time.
+//
+const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding )
+{
+	// Oddly, not supported on some comilers,
+	//name->clear();
+	// So use this:
+	*name = "";
+	assert( p );
+
+	// Names start with letters or underscores.
+	// Of course, in unicode, tinyxml has no idea what a letter *is*. The
+	// algorithm is generous.
+	//
+	// After that, they can be letters, underscores, numbers,
+	// hyphens, or colons. (Colons are valid ony for namespaces,
+	// but tinyxml can't tell namespaces from names.)
+	if (    p && *p 
+		 && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) )
+	{
+		const char* start = p;
+		while(		p && *p
+				&&	(		IsAlphaNum( (unsigned char ) *p, encoding ) 
+						 || *p == '_'
+						 || *p == '-'
+						 || *p == '.'
+						 || *p == ':' ) )
+		{
+			//(*name) += *p; // expensive
+			++p;
+		}
+		if ( p-start > 0 ) {
+			name->assign( start, p-start );
+		}
+		return p;
+	}
+	return 0;
+}
+
+const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )
+{
+	// Presume an entity, and pull it out.
+    TIXML_STRING ent;
+	int i;
+	*length = 0;
+
+	if ( *(p+1) && *(p+1) == '#' && *(p+2) )
+	{
+		unsigned long ucs = 0;
+		ptrdiff_t delta = 0;
+		unsigned mult = 1;
+
+		if ( *(p+2) == 'x' )
+		{
+			// Hexadecimal.
+			if ( !*(p+3) ) return 0;
+
+			const char* q = p+3;
+			q = strchr( q, ';' );
+
+			if ( !q || !*q ) return 0;
+
+			delta = q-p;
+			--q;
+
+			while ( *q != 'x' )
+			{
+				if ( *q >= '0' && *q <= '9' )
+					ucs += mult * (*q - '0');
+				else if ( *q >= 'a' && *q <= 'f' )
+					ucs += mult * (*q - 'a' + 10);
+				else if ( *q >= 'A' && *q <= 'F' )
+					ucs += mult * (*q - 'A' + 10 );
+				else 
+					return 0;
+				mult *= 16;
+				--q;
+			}
+		}
+		else
+		{
+			// Decimal.
+			if ( !*(p+2) ) return 0;
+
+			const char* q = p+2;
+			q = strchr( q, ';' );
+
+			if ( !q || !*q ) return 0;
+
+			delta = q-p;
+			--q;
+
+			while ( *q != '#' )
+			{
+				if ( *q >= '0' && *q <= '9' )
+					ucs += mult * (*q - '0');
+				else 
+					return 0;
+				mult *= 10;
+				--q;
+			}
+		}
+		if ( encoding == TIXML_ENCODING_UTF8 )
+		{
+			// convert the UCS to UTF-8
+			ConvertUTF32ToUTF8( ucs, value, length );
+		}
+		else
+		{
+			*value = (char)ucs;
+			*length = 1;
+		}
+		return p + delta + 1;
+	}
+
+	// Now try to match it.
+	for( i=0; i<NUM_ENTITY; ++i )
+	{
+		if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
+		{
+			assert( strlen( entity[i].str ) == entity[i].strLength );
+			*value = entity[i].chr;
+			*length = 1;
+			return ( p + entity[i].strLength );
+		}
+	}
+
+	// So it wasn't an entity, its unrecognized, or something like that.
+	*value = *p;	// Don't put back the last one, since we return it!
+	//*length = 1;	// Leave unrecognized entities - this doesn't really work.
+					// Just writes strange XML.
+	return p+1;
+}
+
+
+bool TiXmlBase::StringEqual( const char* p,
+							 const char* tag,
+							 bool ignoreCase,
+							 TiXmlEncoding encoding )
+{
+	assert( p );
+	assert( tag );
+	if ( !p || !*p )
+	{
+		assert( 0 );
+		return false;
+	}
+
+	const char* q = p;
+
+	if ( ignoreCase )
+	{
+		while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )
+		{
+			++q;
+			++tag;
+		}
+
+		if ( *tag == 0 )
+			return true;
+	}
+	else
+	{
+		while ( *q && *tag && *q == *tag )
+		{
+			++q;
+			++tag;
+		}
+
+		if ( *tag == 0 )		// Have we found the end of the tag, and everything equal?
+			return true;
+	}
+	return false;
+}
+
+const char* TiXmlBase::ReadText(	const char* p, 
+									TIXML_STRING * text, 
+									bool trimWhiteSpace, 
+									const char* endTag, 
+									bool caseInsensitive,
+									TiXmlEncoding encoding )
+{
+    *text = "";
+	if (    !trimWhiteSpace			// certain tags always keep whitespace
+		 || !condenseWhiteSpace )	// if true, whitespace is always kept
+	{
+		// Keep all the white space.
+		while (	   p && *p
+				&& !StringEqual( p, endTag, caseInsensitive, encoding )
+			  )
+		{
+			int len;
+			char cArr[4] = { 0, 0, 0, 0 };
+			p = GetChar( p, cArr, &len, encoding );
+			text->append( cArr, len );
+		}
+	}
+	else
+	{
+		bool whitespace = false;
+
+		// Remove leading white space:
+		p = SkipWhiteSpace( p, encoding );
+		while (	   p && *p
+				&& !StringEqual( p, endTag, caseInsensitive, encoding ) )
+		{
+			if ( *p == '\r' || *p == '\n' )
+			{
+				whitespace = true;
+				++p;
+			}
+			else if ( IsWhiteSpace( *p ) )
+			{
+				whitespace = true;
+				++p;
+			}
+			else
+			{
+				// If we've found whitespace, add it before the
+				// new character. Any whitespace just becomes a space.
+				if ( whitespace )
+				{
+					(*text) += ' ';
+					whitespace = false;
+				}
+				int len;
+				char cArr[4] = { 0, 0, 0, 0 };
+				p = GetChar( p, cArr, &len, encoding );
+				if ( len == 1 )
+					(*text) += cArr[0];	// more efficient
+				else
+					text->append( cArr, len );
+			}
+		}
+	}
+	if ( p && *p )
+		p += strlen( endTag );
+	return ( p && *p ) ? p : 0;
+}
+
+#ifdef TIXML_USE_STL
+
+void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+	// The basic issue with a document is that we don't know what we're
+	// streaming. Read something presumed to be a tag (and hope), then
+	// identify it, and call the appropriate stream method on the tag.
+	//
+	// This "pre-streaming" will never read the closing ">" so the
+	// sub-tag can orient itself.
+
+	if ( !StreamTo( in, '<', tag ) ) 
+	{
+		SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return;
+	}
+
+	while ( in->good() )
+	{
+		int tagIndex = (int) tag->length();
+		while ( in->good() && in->peek() != '>' )
+		{
+			int c = in->get();
+			if ( c <= 0 )
+			{
+				SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+				break;
+			}
+			(*tag) += (char) c;
+		}
+
+		if ( in->good() )
+		{
+			// We now have something we presume to be a node of 
+			// some sort. Identify it, and call the node to
+			// continue streaming.
+			TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );
+
+			if ( node )
+			{
+				node->StreamIn( in, tag );
+				bool isElement = node->ToElement() != 0;
+				delete node;
+				node = 0;
+
+				// If this is the root element, we're done. Parsing will be
+				// done by the >> operator.
+				if ( isElement )
+				{
+					return;
+				}
+			}
+			else
+			{
+				SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
+				return;
+			}
+		}
+	}
+	// We should have returned sooner.
+	SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
+}
+
+#endif
+
+const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )
+{
+	ClearError();
+
+	// Parse away, at the document level. Since a document
+	// contains nothing but other tags, most of what happens
+	// here is skipping white space.
+	if ( !p || !*p )
+	{
+		SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return 0;
+	}
+
+	// Note that, for a document, this needs to come
+	// before the while space skip, so that parsing
+	// starts from the pointer we are given.
+	location.Clear();
+	if ( prevData )
+	{
+		location.row = prevData->cursor.row;
+		location.col = prevData->cursor.col;
+	}
+	else
+	{
+		location.row = 0;
+		location.col = 0;
+	}
+	TiXmlParsingData data( p, TabSize(), location.row, location.col );
+	location = data.Cursor();
+
+	if ( encoding == TIXML_ENCODING_UNKNOWN )
+	{
+		// Check for the Microsoft UTF-8 lead bytes.
+		const unsigned char* pU = (const unsigned char*)p;
+		if (	*(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0
+			 && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1
+			 && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )
+		{
+			encoding = TIXML_ENCODING_UTF8;
+			useMicrosoftBOM = true;
+		}
+	}
+
+    p = SkipWhiteSpace( p, encoding );
+	if ( !p )
+	{
+		SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
+		return 0;
+	}
+
+	while ( p && *p )
+	{
+		TiXmlNode* node = Identify( p, encoding );
+		if ( node )
+		{
+			p = node->Parse( p, &data, encoding );
+			LinkEndChild( node );
+		}
+		else
+		{
+			break;
+		}
+
+		// Did we get encoding info?
+		if (    encoding == TIXML_ENCODING_UNKNOWN
+			 && node->ToDeclaration() )
+		{
+			TiXmlDeclaration* dec = node->ToDeclaration();
+			const char* enc = dec->Encoding();
+			assert( enc );
+
+			if ( *enc == 0 )
+				encoding = TIXML_ENCODING_UTF8;
+			else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) )
+				encoding = TIXML_ENCODING_UTF8;
+			else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) )
+				encoding = TIXML_ENCODING_UTF8;	// incorrect, but be nice
+			else 
+				encoding = TIXML_ENCODING_LEGACY;
+		}
+
+		p = SkipWhiteSpace( p, encoding );
+	}
+
+	// Was this empty?
+	if ( !firstChild ) {
+		SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );
+		return 0;
+	}
+
+	// All is well.
+	return p;
+}
+
+void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding )
+{	
+	// The first error in a chain is more accurate - don't set again!
+	if ( error )
+		return;
+
+	assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );
+	error   = true;
+	errorId = err;
+	errorDesc = errorString[ errorId ];
+
+	errorLocation.Clear();
+	if ( pError && data )
+	{
+		data->Stamp( pError, encoding );
+		errorLocation = data->Cursor();
+	}
+}
+
+
+TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )
+{
+	TiXmlNode* returnNode = 0;
+
+	p = SkipWhiteSpace( p, encoding );
+	if( !p || !*p || *p != '<' )
+	{
+		return 0;
+	}
+
+	p = SkipWhiteSpace( p, encoding );
+
+	if ( !p || !*p )
+	{
+		return 0;
+	}
+
+	// What is this thing? 
+	// - Elements start with a letter or underscore, but xml is reserved.
+	// - Comments: <!--
+	// - Decleration: <?xml
+	// - Everthing else is unknown to tinyxml.
+	//
+
+	const char* xmlHeader = { "<?xml" };
+	const char* commentHeader = { "<!--" };
+	const char* dtdHeader = { "<!" };
+	const char* cdataHeader = { "<![CDATA[" };
+
+	if ( StringEqual( p, xmlHeader, true, encoding ) )
+	{
+		#ifdef DEBUG_PARSER
+			TIXML_LOG( "XML parsing Declaration\n" );
+		#endif
+		returnNode = new TiXmlDeclaration();
+	}
+	else if ( StringEqual( p, commentHeader, false, encoding ) )
+	{
+		#ifdef DEBUG_PARSER
+			TIXML_LOG( "XML parsing Comment\n" );
+		#endif
+		returnNode = new TiXmlComment();
+	}
+	else if ( StringEqual( p, cdataHeader, false, encoding ) )
+	{
+		#ifdef DEBUG_PARSER
+			TIXML_LOG( "XML parsing CDATA\n" );
+		#endif
+		TiXmlText* text = new TiXmlText( "" );
+		text->SetCDATA( true );
+		returnNode = text;
+	}
+	else if ( StringEqual( p, dtdHeader, false, encoding ) )
+	{
+		#ifdef DEBUG_PARSER
+			TIXML_LOG( "XML parsing Unknown(1)\n" );
+		#endif
+		returnNode = new TiXmlUnknown();
+	}
+	else if (    IsAlpha( *(p+1), encoding )
+			  || *(p+1) == '_' )
+	{
+		#ifdef DEBUG_PARSER
+			TIXML_LOG( "XML parsing Element\n" );
+		#endif
+		returnNode = new TiXmlElement( "" );
+	}
+	else
+	{
+		#ifdef DEBUG_PARSER
+			TIXML_LOG( "XML parsing Unknown(2)\n" );
+		#endif
+		returnNode = new TiXmlUnknown();
+	}
+
+	if ( returnNode )
+	{
+		// Set the parent, so it can report errors
+		returnNode->parent = this;
+	}
+	return returnNode;
+}
+
+#ifdef TIXML_USE_STL
+
+void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)
+{
+	// We're called with some amount of pre-parsing. That is, some of "this"
+	// element is in "tag". Go ahead and stream to the closing ">"
+	while( in->good() )
+	{
+		int c = in->get();
+		if ( c <= 0 )
+		{
+			TiXmlDocument* document = GetDocument();
+			if ( document )
+				document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+			return;
+		}
+		(*tag) += (char) c ;
+		
+		if ( c == '>' )
+			break;
+	}
+
+	if ( tag->length() < 3 ) return;
+
+	// Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
+	// If not, identify and stream.
+
+	if (    tag->at( tag->length() - 1 ) == '>' 
+		 && tag->at( tag->length() - 2 ) == '/' )
+	{
+		// All good!
+		return;
+	}
+	else if ( tag->at( tag->length() - 1 ) == '>' )
+	{
+		// There is more. Could be:
+		//		text
+		//		cdata text (which looks like another node)
+		//		closing tag
+		//		another node.
+		for ( ;; )
+		{
+			StreamWhiteSpace( in, tag );
+
+			// Do we have text?
+			if ( in->good() && in->peek() != '<' ) 
+			{
+				// Yep, text.
+				TiXmlText text( "" );
+				text.StreamIn( in, tag );
+
+				// What follows text is a closing tag or another node.
+				// Go around again and figure it out.
+				continue;
+			}
+
+			// We now have either a closing tag...or another node.
+			// We should be at a "<", regardless.
+			if ( !in->good() ) return;
+			assert( in->peek() == '<' );
+			int tagIndex = (int) tag->length();
+
+			bool closingTag = false;
+			bool firstCharFound = false;
+
+			for( ;; )
+			{
+				if ( !in->good() )
+					return;
+
+				int c = in->peek();
+				if ( c <= 0 )
+				{
+					TiXmlDocument* document = GetDocument();
+					if ( document )
+						document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+					return;
+				}
+				
+				if ( c == '>' )
+					break;
+
+				*tag += (char) c;
+				in->get();
+
+				// Early out if we find the CDATA id.
+				if ( c == '[' && tag->size() >= 9 )
+				{
+					size_t len = tag->size();
+					const char* start = tag->c_str() + len - 9;
+					if ( strcmp( start, "<![CDATA[" ) == 0 ) {
+						assert( !closingTag );
+						break;
+					}
+				}
+
+				if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
+				{
+					firstCharFound = true;
+					if ( c == '/' )
+						closingTag = true;
+				}
+			}
+			// If it was a closing tag, then read in the closing '>' to clean up the input stream.
+			// If it was not, the streaming will be done by the tag.
+			if ( closingTag )
+			{
+				if ( !in->good() )
+					return;
+
+				int c = in->get();
+				if ( c <= 0 )
+				{
+					TiXmlDocument* document = GetDocument();
+					if ( document )
+						document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+					return;
+				}
+				assert( c == '>' );
+				*tag += (char) c;
+
+				// We are done, once we've found our closing tag.
+				return;
+			}
+			else
+			{
+				// If not a closing tag, id it, and stream.
+				const char* tagloc = tag->c_str() + tagIndex;
+				TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );
+				if ( !node )
+					return;
+				node->StreamIn( in, tag );
+				delete node;
+				node = 0;
+
+				// No return: go around from the beginning: text, closing tag, or node.
+			}
+		}
+	}
+}
+#endif
+
+const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+	p = SkipWhiteSpace( p, encoding );
+	TiXmlDocument* document = GetDocument();
+
+	if ( !p || !*p )
+	{
+		if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
+		return 0;
+	}
+
+	if ( data )
+	{
+		data->Stamp( p, encoding );
+		location = data->Cursor();
+	}
+
+	if ( *p != '<' )
+	{
+		if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
+		return 0;
+	}
+
+	p = SkipWhiteSpace( p+1, encoding );
+
+	// Read the name.
+	const char* pErr = p;
+
+    p = ReadName( p, &value, encoding );
+	if ( !p || !*p )
+	{
+		if ( document )	document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
+		return 0;
+	}
+
+    TIXML_STRING endTag ("</");
+	endTag += value;
+
+	// Check for and read attributes. Also look for an empty
+	// tag or an end tag.
+	while ( p && *p )
+	{
+		pErr = p;
+		p = SkipWhiteSpace( p, encoding );
+		if ( !p || !*p )
+		{
+			if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
+			return 0;
+		}
+		if ( *p == '/' )
+		{
+			++p;
+			// Empty tag.
+			if ( *p  != '>' )
+			{
+				if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );		
+				return 0;
+			}
+			return (p+1);
+		}
+		else if ( *p == '>' )
+		{
+			// Done with attributes (if there were any.)
+			// Read the value -- which can include other
+			// elements -- read the end tag, and return.
+			++p;
+			p = ReadValue( p, data, encoding );		// Note this is an Element method, and will set the error if one happens.
+			if ( !p || !*p ) {
+				// We were looking for the end tag, but found nothing.
+				// Fix for [ 1663758 ] Failure to report error on bad XML
+				if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
+				return 0;
+			}
+
+			// We should find the end tag now
+			// note that:
+			// </foo > and
+			// </foo> 
+			// are both valid end tags.
+			if ( StringEqual( p, endTag.c_str(), false, encoding ) )
+			{
+				p += endTag.length();
+				p = SkipWhiteSpace( p, encoding );
+				if ( p && *p && *p == '>' ) {
+					++p;
+					return p;
+				}
+				if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
+				return 0;
+			}
+			else
+			{
+				if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
+				return 0;
+			}
+		}
+		else
+		{
+			// Try to read an attribute:
+			TiXmlAttribute* attrib = new TiXmlAttribute();
+			if ( !attrib )
+			{
+				return 0;
+			}
+
+			attrib->SetDocument( document );
+			pErr = p;
+			p = attrib->Parse( p, data, encoding );
+
+			if ( !p || !*p )
+			{
+				if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
+				delete attrib;
+				return 0;
+			}
+
+			// Handle the strange case of double attributes:
+			#ifdef TIXML_USE_STL
+			TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );
+			#else
+			TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
+			#endif
+			if ( node )
+			{
+				if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
+				delete attrib;
+				return 0;
+			}
+
+			attributeSet.Add( attrib );
+		}
+	}
+	return p;
+}
+
+
+const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+	TiXmlDocument* document = GetDocument();
+
+	// Read in text and elements in any order.
+	const char* pWithWhiteSpace = p;
+	p = SkipWhiteSpace( p, encoding );
+
+	while ( p && *p )
+	{
+		if ( *p != '<' )
+		{
+			// Take what we have, make a text element.
+			TiXmlText* textNode = new TiXmlText( "" );
+
+			if ( !textNode )
+			{
+			    return 0;
+			}
+
+			if ( TiXmlBase::IsWhiteSpaceCondensed() )
+			{
+				p = textNode->Parse( p, data, encoding );
+			}
+			else
+			{
+				// Special case: we want to keep the white space
+				// so that leading spaces aren't removed.
+				p = textNode->Parse( pWithWhiteSpace, data, encoding );
+			}
+
+			if ( !textNode->Blank() )
+				LinkEndChild( textNode );
+			else
+				delete textNode;
+		} 
+		else 
+		{
+			// We hit a '<'
+			// Have we hit a new element or an end tag? This could also be
+			// a TiXmlText in the "CDATA" style.
+			if ( StringEqual( p, "</", false, encoding ) )
+			{
+				return p;
+			}
+			else
+			{
+				TiXmlNode* node = Identify( p, encoding );
+				if ( node )
+				{
+					p = node->Parse( p, data, encoding );
+					LinkEndChild( node );
+				}				
+				else
+				{
+					return 0;
+				}
+			}
+		}
+		pWithWhiteSpace = p;
+		p = SkipWhiteSpace( p, encoding );
+	}
+
+	if ( !p )
+	{
+		if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );
+	}	
+	return p;
+}
+
+
+#ifdef TIXML_USE_STL
+void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+	while ( in->good() )
+	{
+		int c = in->get();	
+		if ( c <= 0 )
+		{
+			TiXmlDocument* document = GetDocument();
+			if ( document )
+				document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+			return;
+		}
+		(*tag) += (char) c;
+
+		if ( c == '>' )
+		{
+			// All is well.
+			return;		
+		}
+	}
+}
+#endif
+
+
+const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+	TiXmlDocument* document = GetDocument();
+	p = SkipWhiteSpace( p, encoding );
+
+	if ( data )
+	{
+		data->Stamp( p, encoding );
+		location = data->Cursor();
+	}
+	if ( !p || !*p || *p != '<' )
+	{
+		if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );
+		return 0;
+	}
+	++p;
+    value = "";
+
+	while ( p && *p && *p != '>' )
+	{
+		value += *p;
+		++p;
+	}
+
+	if ( !p )
+	{
+		if ( document )	
+			document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
+	}
+	if ( p && *p == '>' )
+		return p+1;
+	return p;
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+	while ( in->good() )
+	{
+		int c = in->get();	
+		if ( c <= 0 )
+		{
+			TiXmlDocument* document = GetDocument();
+			if ( document )
+				document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+			return;
+		}
+
+		(*tag) += (char) c;
+
+		if ( c == '>' 
+			 && tag->at( tag->length() - 2 ) == '-'
+			 && tag->at( tag->length() - 3 ) == '-' )
+		{
+			// All is well.
+			return;		
+		}
+	}
+}
+#endif
+
+
+const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+	TiXmlDocument* document = GetDocument();
+	value = "";
+
+	p = SkipWhiteSpace( p, encoding );
+
+	if ( data )
+	{
+		data->Stamp( p, encoding );
+		location = data->Cursor();
+	}
+	const char* startTag = "<!--";
+	const char* endTag   = "-->";
+
+	if ( !StringEqual( p, startTag, false, encoding ) )
+	{
+		if ( document )
+			document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );
+		return 0;
+	}
+	p += strlen( startTag );
+
+	// [ 1475201 ] TinyXML parses entities in comments
+	// Oops - ReadText doesn't work, because we don't want to parse the entities.
+	// p = ReadText( p, &value, false, endTag, false, encoding );
+	//
+	// from the XML spec:
+	/*
+	 [Definition: Comments may appear anywhere in a document outside other markup; in addition, 
+	              they may appear within the document type declaration at places allowed by the grammar. 
+				  They are not part of the document's character data; an XML processor MAY, but need not, 
+				  make it possible for an application to retrieve the text of comments. For compatibility, 
+				  the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity 
+				  references MUST NOT be recognized within comments.
+
+				  An example of a comment:
+
+				  <!-- declarations for <head> & <body> -->
+	*/
+
+    value = "";
+	// Keep all the white space.
+	while (	p && *p && !StringEqual( p, endTag, false, encoding ) )
+	{
+		value.append( p, 1 );
+		++p;
+	}
+	if ( p && *p ) 
+		p += strlen( endTag );
+
+	return p;
+}
+
+
+const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+	p = SkipWhiteSpace( p, encoding );
+	if ( !p || !*p ) return 0;
+
+	if ( data )
+	{
+		data->Stamp( p, encoding );
+		location = data->Cursor();
+	}
+	// Read the name, the '=' and the value.
+	const char* pErr = p;
+	p = ReadName( p, &name, encoding );
+	if ( !p || !*p )
+	{
+		if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
+		return 0;
+	}
+	p = SkipWhiteSpace( p, encoding );
+	if ( !p || !*p || *p != '=' )
+	{
+		if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+		return 0;
+	}
+
+	++p;	// skip '='
+	p = SkipWhiteSpace( p, encoding );
+	if ( !p || !*p )
+	{
+		if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+		return 0;
+	}
+	
+	const char* end;
+	const char SINGLE_QUOTE = '\'';
+	const char DOUBLE_QUOTE = '\"';
+
+	if ( *p == SINGLE_QUOTE )
+	{
+		++p;
+		end = "\'";		// single quote in string
+		p = ReadText( p, &value, false, end, false, encoding );
+	}
+	else if ( *p == DOUBLE_QUOTE )
+	{
+		++p;
+		end = "\"";		// double quote in string
+		p = ReadText( p, &value, false, end, false, encoding );
+	}
+	else
+	{
+		// All attribute values should be in single or double quotes.
+		// But this is such a common error that the parser will try
+		// its best, even without them.
+		value = "";
+		while (    p && *p											// existence
+				&& !IsWhiteSpace( *p )								// whitespace
+				&& *p != '/' && *p != '>' )							// tag end
+		{
+			if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) {
+				// [ 1451649 ] Attribute values with trailing quotes not handled correctly
+				// We did not have an opening quote but seem to have a 
+				// closing one. Give up and throw an error.
+				if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
+				return 0;
+			}
+			value += *p;
+			++p;
+		}
+	}
+	return p;
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+	while ( in->good() )
+	{
+		int c = in->peek();	
+		if ( !cdata && (c == '<' ) ) 
+		{
+			return;
+		}
+		if ( c <= 0 )
+		{
+			TiXmlDocument* document = GetDocument();
+			if ( document )
+				document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+			return;
+		}
+
+		(*tag) += (char) c;
+		in->get();	// "commits" the peek made above
+
+		if ( cdata && c == '>' && tag->size() >= 3 ) {
+			size_t len = tag->size();
+			if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) {
+				// terminator of cdata.
+				return;
+			}
+		}    
+	}
+}
+#endif
+
+const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
+{
+	value = "";
+	TiXmlDocument* document = GetDocument();
+
+	if ( data )
+	{
+		data->Stamp( p, encoding );
+		location = data->Cursor();
+	}
+
+	const char* const startTag = "<![CDATA[";
+	const char* const endTag   = "]]>";
+
+	if ( cdata || StringEqual( p, startTag, false, encoding ) )
+	{
+		cdata = true;
+
+		if ( !StringEqual( p, startTag, false, encoding ) )
+		{
+			if ( document )
+				document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );
+			return 0;
+		}
+		p += strlen( startTag );
+
+		// Keep all the white space, ignore the encoding, etc.
+		while (	   p && *p
+				&& !StringEqual( p, endTag, false, encoding )
+			  )
+		{
+			value += *p;
+			++p;
+		}
+
+		TIXML_STRING dummy; 
+		p = ReadText( p, &dummy, false, endTag, false, encoding );
+		return p;
+	}
+	else
+	{
+		bool ignoreWhite = true;
+
+		const char* end = "<";
+		p = ReadText( p, &value, ignoreWhite, end, false, encoding );
+		if ( p && *p )
+			return p-1;	// don't truncate the '<'
+		return 0;
+	}
+}
+
+#ifdef TIXML_USE_STL
+void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag )
+{
+	while ( in->good() )
+	{
+		int c = in->get();
+		if ( c <= 0 )
+		{
+			TiXmlDocument* document = GetDocument();
+			if ( document )
+				document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
+			return;
+		}
+		(*tag) += (char) c;
+
+		if ( c == '>' )
+		{
+			// All is well.
+			return;
+		}
+	}
+}
+#endif
+
+const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )
+{
+	p = SkipWhiteSpace( p, _encoding );
+	// Find the beginning, find the end, and look for
+	// the stuff in-between.
+	TiXmlDocument* document = GetDocument();
+	if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) )
+	{
+		if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );
+		return 0;
+	}
+	if ( data )
+	{
+		data->Stamp( p, _encoding );
+		location = data->Cursor();
+	}
+	p += 5;
+
+	version = "";
+	encoding = "";
+	standalone = "";
+
+	while ( p && *p )
+	{
+		if ( *p == '>' )
+		{
+			++p;
+			return p;
+		}
+
+		p = SkipWhiteSpace( p, _encoding );
+		if ( StringEqual( p, "version", true, _encoding ) )
+		{
+			TiXmlAttribute attrib;
+			p = attrib.Parse( p, data, _encoding );		
+			version = attrib.Value();
+		}
+		else if ( StringEqual( p, "encoding", true, _encoding ) )
+		{
+			TiXmlAttribute attrib;
+			p = attrib.Parse( p, data, _encoding );		
+			encoding = attrib.Value();
+		}
+		else if ( StringEqual( p, "standalone", true, _encoding ) )
+		{
+			TiXmlAttribute attrib;
+			p = attrib.Parse( p, data, _encoding );		
+			standalone = attrib.Value();
+		}
+		else
+		{
+			// Read over whatever it is.
+			while( p && *p && *p != '>' && !IsWhiteSpace( *p ) )
+				++p;
+		}
+	}
+	return 0;
+}
+
+bool TiXmlText::Blank() const
+{
+	for ( unsigned i=0; i<value.length(); i++ )
+		if ( !IsWhiteSpace( value[i] ) )
+			return false;
+	return true;
+}
+
diff --git a/cpp/src/test/verify_glyf.cc b/cpp/src/test/verify_glyf.cc
new file mode 100644
index 0000000..abfe1ab
--- /dev/null
+++ b/cpp/src/test/verify_glyf.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/table/truetype/glyph_table.h"
+#include "test/serialization_test.h"
+
+namespace sfntly {
+
+// We spot check only glyph id 33.
+const int32_t GLYPH33_OFFSET = 0xAC8;
+const int32_t GLYPH33_LENGTH = 40;
+const int32_t GLYPH33_XMIN = 92;
+const int32_t GLYPH33_YMIN = 20;
+const int32_t GLYPH33_XMAX = 797;
+const int32_t GLYPH33_YMAX = 1235;
+
+// TODO(arthurhsu): Tuffy does not have composite glyphs.  Need better testing.
+static bool VerifyGLYF(Table* table) {
+  GlyphTablePtr glyf_table = down_cast<GlyphTable*>(table);
+  if (glyf_table == NULL) {
+    return false;
+  }
+
+  GlyphPtr glyf;
+  glyf.Attach(glyf_table->GetGlyph(GLYPH33_OFFSET, GLYPH33_LENGTH));
+  if (glyf == NULL) {
+    return false;
+  }
+
+  EXPECT_EQ(glyf->XMin(), GLYPH33_XMIN);
+  EXPECT_EQ(glyf->YMin(), GLYPH33_YMIN);
+  EXPECT_EQ(glyf->XMax(), GLYPH33_XMAX);
+  EXPECT_EQ(glyf->YMax(), GLYPH33_YMAX);
+
+  return true;
+}
+
+bool VerifyGLYF(Table* original, Table* target) {
+  EXPECT_TRUE(VerifyGLYF(original));
+  EXPECT_TRUE(VerifyGLYF(target));
+  return true;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/test/verify_hhea.cc b/cpp/src/test/verify_hhea.cc
new file mode 100644
index 0000000..81ddb58
--- /dev/null
+++ b/cpp/src/test/verify_hhea.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/math/fixed1616.h"
+#include "sfntly/table/core/horizontal_header_table.h"
+#include "test/serialization_test.h"
+
+namespace sfntly {
+
+const int32_t HHEA_ASCENDER = 2023;
+const int32_t HHEA_DESCENDER = -648;
+const int32_t HHEA_LINE_GAP = 93;
+const int32_t HHEA_ADVANCE_WIDTH_MAX = 2753;
+const int32_t HHEA_MIN_LSB = -968;
+const int32_t HHEA_MIN_RSB = -411;
+const int32_t HHEA_X_MAX_EXTENT = 2628;
+const int32_t HHEA_METRIC_DATA_FORMAT = 0;
+const int32_t HHEA_NUM_METRICS = 1499;
+
+static bool VerifyHHEA(Table* table) {
+  HorizontalHeaderTablePtr hhea = down_cast<HorizontalHeaderTable*>(table);
+  if (hhea == NULL) {
+    return false;
+  }
+
+  EXPECT_EQ(hhea->TableVersion(), Fixed1616::Fixed(1, 0));
+  EXPECT_EQ(hhea->Ascender(), HHEA_ASCENDER);
+  EXPECT_EQ(hhea->Descender(), HHEA_DESCENDER);
+  EXPECT_EQ(hhea->AdvanceWidthMax(), HHEA_ADVANCE_WIDTH_MAX);
+  EXPECT_EQ(hhea->MinLeftSideBearing(), HHEA_MIN_LSB);
+  EXPECT_EQ(hhea->MinRightSideBearing(), HHEA_MIN_RSB);
+  EXPECT_EQ(hhea->XMaxExtent(), HHEA_X_MAX_EXTENT);
+  // TODO(arthurhsu): CaretSlopeRise() not tested
+  // TODO(arthurhsu): CaretSlopeRun() not tested
+  // TODO(arthurhsu): CaretOffset() not tested
+  EXPECT_EQ(hhea->MetricDataFormat(), HHEA_METRIC_DATA_FORMAT);
+  EXPECT_EQ(hhea->NumberOfHMetrics(), HHEA_NUM_METRICS);
+
+  return true;
+}
+
+bool VerifyHHEA(Table* original, Table* target) {
+  EXPECT_TRUE(VerifyHHEA(original));
+  EXPECT_TRUE(VerifyHHEA(target));
+  return true;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/test/verify_hmtx.cc b/cpp/src/test/verify_hmtx.cc
new file mode 100644
index 0000000..d37bba9
--- /dev/null
+++ b/cpp/src/test/verify_hmtx.cc
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/table/core/horizontal_metrics_table.h"
+#include "test/serialization_test.h"
+
+namespace sfntly {
+
+const int32_t HMTX_ENTRIES_COUNT = 1499;
+const int32_t HMTX_LSB_COUNT = 3;
+
+struct HmtxEntry {
+  int32_t advance_width_;
+  int32_t lsb_;
+
+  HmtxEntry(int32_t advance_width, int32_t lsb)
+      : advance_width_(advance_width), lsb_(lsb) {}
+};
+
+const HmtxEntry HMTX_ENTRIES[] = {
+    HmtxEntry(748, 68),  // 0
+    HmtxEntry(0, 0),  // 1
+    HmtxEntry(682, 0),  // 2
+    HmtxEntry(616, 0),  // 3
+    HmtxEntry(421, 103),  // 4
+    HmtxEntry(690, 129),  // 5
+    HmtxEntry(1589, 129),  // 6
+    HmtxEntry(1017, 25),  // 7
+    HmtxEntry(1402, 104),  // 8
+    HmtxEntry(1241, 100),  // 9
+};
+const int32_t NUM_HMTX_ENTRIES = 10;
+
+static bool VerifyHMTX(Table* table) {
+  HorizontalMetricsTablePtr hmtx = down_cast<HorizontalMetricsTable*>(table);
+  if (hmtx == NULL) {
+    return false;
+  }
+
+  EXPECT_EQ(hmtx->NumberOfHMetrics(), HMTX_ENTRIES_COUNT);
+  EXPECT_EQ(hmtx->NumberOfLSBs(), HMTX_LSB_COUNT);
+
+  for (int32_t i = 0; i < NUM_HMTX_ENTRIES; ++i) {
+    EXPECT_EQ(hmtx->AdvanceWidth(i), HMTX_ENTRIES[i].advance_width_);
+    EXPECT_EQ(hmtx->LeftSideBearing(i), HMTX_ENTRIES[i].lsb_);
+  }
+
+  // No such element case.
+  EXPECT_EQ(hmtx->AdvanceWidth(HMTX_ENTRIES_COUNT),
+            HMTX_ENTRIES[0].advance_width_);
+  EXPECT_EQ(hmtx->LeftSideBearing(HMTX_ENTRIES_COUNT), HMTX_ENTRIES[0].lsb_);
+  return true;
+}
+
+bool VerifyHMTX(Table* original, Table* target) {
+  EXPECT_TRUE(VerifyHMTX(original));
+  EXPECT_TRUE(VerifyHMTX(target));
+  return true;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/test/verify_loca.cc b/cpp/src/test/verify_loca.cc
new file mode 100644
index 0000000..4a32928
--- /dev/null
+++ b/cpp/src/test/verify_loca.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/table/truetype/loca_table.h"
+#include "test/serialization_test.h"
+
+namespace sfntly {
+
+const int32_t LOCA_NUM_LOCAS = 1503;
+const int32_t LOCAS[] = {
+    0x00000,  // 0
+    0x00058,  // 1
+    0x00058,  // 2
+    0x00058,  // 3
+    0x00058,  // 4
+    0x000B8,  // 5
+    0x00138,  // 6
+    0x001A4,  // 7
+    0x0025C,  // 8
+    0x00328,  // 9
+    0x003B8,  // 10
+};
+const int32_t NUM_TEST_LOCAS = 11;
+
+static bool VerifyLOCA(Table* table) {
+  LocaTablePtr loca = down_cast<LocaTable*>(table);
+  if (loca == NULL) {
+    return false;
+  }
+
+  EXPECT_EQ(loca->NumLocas(), LOCA_NUM_LOCAS);
+  EXPECT_EQ(loca->num_glyphs(), LOCA_NUM_LOCAS - 1);
+
+  for (int32_t i = 0; i < NUM_TEST_LOCAS - 1; ++i) {
+    EXPECT_EQ(loca->GlyphOffset(i), LOCAS[i]);
+    EXPECT_EQ(loca->GlyphLength(i), LOCAS[i + 1] - LOCAS[i]);
+  }
+  return true;
+}
+
+bool VerifyLOCA(Table* original, Table* target) {
+  EXPECT_TRUE(VerifyLOCA(original));
+  EXPECT_TRUE(VerifyLOCA(target));
+  return true;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/test/verify_maxp.cc b/cpp/src/test/verify_maxp.cc
new file mode 100644
index 0000000..dcd776e
--- /dev/null
+++ b/cpp/src/test/verify_maxp.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/math/fixed1616.h"
+#include "sfntly/table/core/maximum_profile_table.h"
+#include "test/serialization_test.h"
+
+namespace sfntly {
+
+const int32_t MAXP_NUM_GLYPHS = 1502;
+const int32_t MAXP_MAX_POINTS = 181;
+const int32_t MAXP_MAX_CONTOURS = 9;
+const int32_t MAXP_MAX_COMPOSITE_POINTS = 172;
+const int32_t MAXP_MAX_COMPOSITE_CONTOURS = 5;
+const int32_t MAXP_MAX_ZONES = 2;
+const int32_t MAXP_MAX_TWILIGHT_POINTS = 0;
+const int32_t MAXP_MAX_STORAGE = 1;
+const int32_t MAXP_MAX_FUNCTION_DEFS = 1;
+const int32_t MAXP_MAX_INSTR_DEFS = 0;
+const int32_t MAXP_MAX_STACK_ELEMENTS = 64;
+const int32_t MAXP_MAX_INSTR_SIZE = 46;
+const int32_t MAXP_MAX_COMPONENT_ELEMENTS = 4;
+const int32_t MAXP_MAX_COMPONENT_DEPTH = 3;
+
+static bool VerifyMAXP(Table* table) {
+  MaximumProfileTablePtr maxp = down_cast<MaximumProfileTable*>(table);
+  if (maxp == NULL) {
+    return false;
+  }
+
+  EXPECT_EQ(maxp->TableVersion(), Fixed1616::Fixed(1, 0));
+  EXPECT_EQ(maxp->NumGlyphs(), MAXP_NUM_GLYPHS);
+  EXPECT_EQ(maxp->MaxPoints(), MAXP_MAX_POINTS);
+  EXPECT_EQ(maxp->MaxContours(), MAXP_MAX_CONTOURS);
+  EXPECT_EQ(maxp->MaxCompositePoints(), MAXP_MAX_COMPOSITE_POINTS);
+  EXPECT_EQ(maxp->MaxCompositeContours(), MAXP_MAX_COMPOSITE_CONTOURS);
+  EXPECT_EQ(maxp->MaxZones(), MAXP_MAX_ZONES);
+  EXPECT_EQ(maxp->MaxTwilightPoints(), MAXP_MAX_TWILIGHT_POINTS);
+  EXPECT_EQ(maxp->MaxStorage(), MAXP_MAX_STORAGE);
+  EXPECT_EQ(maxp->MaxFunctionDefs(), MAXP_MAX_FUNCTION_DEFS);
+  // TODO(arthurhsu): maxInstructionDefs observed in Microsoft TTF report.
+  //                  Check with stuartg and see if this is a miss.
+  EXPECT_EQ(maxp->MaxStackElements(), MAXP_MAX_STACK_ELEMENTS);
+  EXPECT_EQ(maxp->MaxSizeOfInstructions(), MAXP_MAX_INSTR_SIZE);
+  EXPECT_EQ(maxp->MaxComponentElements(), MAXP_MAX_COMPONENT_ELEMENTS);
+  EXPECT_EQ(maxp->MaxComponentDepth(), MAXP_MAX_COMPONENT_DEPTH);
+
+  return true;
+}
+
+bool VerifyMAXP(Table* original, Table* target) {
+  EXPECT_TRUE(VerifyMAXP(original));
+  EXPECT_TRUE(VerifyMAXP(target));
+  return true;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/test/verify_name.cc b/cpp/src/test/verify_name.cc
new file mode 100644
index 0000000..e1101c0
--- /dev/null
+++ b/cpp/src/test/verify_name.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/table/core/name_table.h"
+#include "test/serialization_test.h"
+
+namespace sfntly {
+
+const int32_t NAME_FORMAT = 0;
+const int32_t NAME_COUNT = 75;
+const NameTable::NameEntryId NAME_IDS[] = {
+    NameTable::NameEntryId(1, 0, 0, 0),  // 0
+    NameTable::NameEntryId(1, 0, 0, 1),  // 1
+    NameTable::NameEntryId(1, 0, 0, 2),  // 2
+    NameTable::NameEntryId(1, 0, 0, 3),  // 3
+    NameTable::NameEntryId(1, 0, 0, 4),  // 4
+    NameTable::NameEntryId(1, 0, 0, 5),  // 5
+    NameTable::NameEntryId(1, 0, 0, 6),  // 6
+    NameTable::NameEntryId(1, 0, 0, 9),  // 7
+    NameTable::NameEntryId(1, 0, 0, 11),  // 8
+    NameTable::NameEntryId(1, 0, 0, 12),  // 9
+};
+const int32_t NAME_IDS_TEST = 10;
+
+static bool VerifyNAME(Table* table) {
+  // TODO(arthurhsu): Better testing can be done here.  Right now we just
+  //                  iterate through the entries and get entry ids.
+  NameTablePtr name = down_cast<NameTable*>(table);
+  if (name == NULL) {
+    return false;
+  }
+
+  EXPECT_EQ(name->Format(), NAME_FORMAT);
+  EXPECT_EQ(name->NameCount(), NAME_COUNT);
+  fprintf(stderr, "checking name entry: ");
+  for (int32_t i = 0; i < NAME_IDS_TEST; ++i) {
+    fprintf(stderr, "%d ", i);
+    EXPECT_EQ(name->PlatformId(i), NAME_IDS[i].platform_id());
+    EXPECT_EQ(name->EncodingId(i), NAME_IDS[i].encoding_id());
+    EXPECT_EQ(name->LanguageId(i), NAME_IDS[i].language_id());
+    EXPECT_EQ(name->NameId(i), NAME_IDS[i].name_id());
+  }
+  fprintf(stderr, "\n");
+  return true;
+}
+
+bool VerifyNAME(Table* original, Table* target) {
+  EXPECT_TRUE(VerifyNAME(original));
+  EXPECT_TRUE(VerifyNAME(target));
+  return true;
+}
+
+}  // namespace sfntly
diff --git a/cpp/src/test/verify_os2.cc b/cpp/src/test/verify_os2.cc
new file mode 100644
index 0000000..4897e87
--- /dev/null
+++ b/cpp/src/test/verify_os2.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gtest/gtest.h"
+#include "sfntly/font.h"
+#include "sfntly/table/core/os2_table.h"
+#include "test/serialization_test.h"
+
+namespace sfntly {
+
+const int32_t OS2_VERSION = 1;
+const int32_t OS2_XAVG_CHAR_WIDTH = 863;
+const int32_t OS2_US_WEIGHT_CLASS = 500;
+const int32_t OS2_US_WIDTH_CLASS = 5;
+const int32_t OS2_FS_TYPE = 0;
+const int32_t OS2_YSUBS_XSIZE = 0;
+const int32_t OS2_YSUBS_YSIZE = 2;
+const int32_t OS2_YSUBS_XOFFSET = -16560;
+const int32_t OS2_YSUBS_YOFFSET = 0;
+const int32_t OS2_YSUPS_XSIZE = -25944;
+const int32_t OS2_YSUPS_YSIZE = -27176;
+const int32_t OS2_YSUPS_XOFFSET = -16376;
+const int32_t OS2_YSUPS_YOFFSET = 1;
+const int32_t OS2_YSTRIKEOUT_SIZE = 12312;
+const int32_t OS2_YSTRIKEOUT_POS = -16224;
+const int32_t OS2_SFAMILY_CLASS = 0;
+const byte_t OS2_PANOSE[] = { 2, 11, 6, 3, 6, 1, 0, 0, 0, 0 };
+const int64_t OS2_UL_UNICODE_RANGE1 = 0xE00002FFL;
+const int64_t OS2_UL_UNICODE_RANGE2 = 0x520020FBL;
+const int64_t OS2_UL_UNICODE_RANGE3 = 0L;
+const int64_t OS2_UL_UNICODE_RANGE4 = 0L;
+const byte_t OS2_ACH_VEND_ID[] = { 'P', 'f', 'E', 'd' };
+const int32_t OS2_FS_SELECTION = 0x0040;
+const int32_t OS2_US_FIRST_CHAR_IDX = 0x0020;
+const int32_t OS2_US_LAST_CHAR_IDX = 0xFFFF;
+const int32_t OS2_STYPO_ASCENDER = 1597;
+const int32_t OS2_STYPO_DESCENDER = -451;
+const int32_t OS2_STYPO_LINE_GAP = 0;
+const int32_t OS2_US_WIN_ASCENT = 2023;
+const int32_t OS2_US_WIN_DESCENT = 648;
+const int64_t OS2_UL_CODE_PAGE_RANGE1 = 0x2000019FL;
+const int64_t OS2_UL_CODE_PAGE_RANGE2 = 0x00000000L;
+
+static bool VerifyOS_2(Table* table) {
+  OS2TablePtr os2 = down_cast<OS2Table*>(table);
+  if (os2 == NULL) {
+    return false;
+  }
+
+  EXPECT_EQ(os2->TableVersion(), OS2_VERSION);
+  EXPECT_EQ(os2->XAvgCharWidth(), OS2_XAVG_CHAR_WIDTH);
+  EXPECT_EQ(os2->UsWeightClass(), OS2_US_WEIGHT_CLASS);
+  EXPECT_EQ(os2->UsWidthClass(), OS2_US_WIDTH_CLASS);
+  EXPECT_EQ(os2->FsType(), OS2_FS_TYPE);
+  EXPECT_EQ(os2->YSubscriptXSize(), OS2_YSUBS_XSIZE);
+  EXPECT_EQ(os2->YSubscriptYSize(), OS2_YSUBS_YSIZE);
+  EXPECT_EQ(os2->YSubscriptXOffset(), OS2_YSUBS_XOFFSET);
+  EXPECT_EQ(os2->YSubscriptYOffset(), OS2_YSUBS_YOFFSET);
+  EXPECT_EQ(os2->YSuperscriptXSize(), OS2_YSUPS_XSIZE);
+  EXPECT_EQ(os2->YSuperscriptYSize(), OS2_YSUPS_YSIZE);
+  EXPECT_EQ(os2->YSuperscriptXOffset(), OS2_YSUPS_XOFFSET);
+  EXPECT_EQ(os2->YSuperscriptYOffset(), OS2_YSUPS_YOFFSET);
+  EXPECT_EQ(os2->YStrikeoutSize(), OS2_YSTRIKEOUT_SIZE);
+  EXPECT_EQ(os2->YStrikeoutPosition(), OS2_YSTRIKEOUT_POS);
+  EXPECT_EQ(os2->SFamilyClass(), OS2_SFAMILY_CLASS);
+
+  ByteVector panose;
+  os2->Panose(&panose);
+  EXPECT_EQ(panose.size(), sizeof(OS2_PANOSE));
+  for (size_t i = 0; i < panose.size(); ++i) {
+    EXPECT_EQ(panose[i], OS2_PANOSE[i]);
+  }
+
+  EXPECT_EQ(os2->UlUnicodeRange1(), OS2_UL_UNICODE_RANGE1);
+  EXPECT_EQ(os2->UlUnicodeRange2(), OS2_UL_UNICODE_RANGE2);
+  EXPECT_EQ(os2->UlUnicodeRange3(), OS2_UL_UNICODE_RANGE3);
+  EXPECT_EQ(os2->UlUnicodeRange4(), OS2_UL_UNICODE_RANGE4);
+
+  ByteVector vend_id;
+  os2->AchVendId(&vend_id);
+  EXPECT_EQ(vend_id.size(), sizeof(OS2_ACH_VEND_ID));
+  for (size_t i = 0; i < vend_id.size(); ++i) {
+    EXPECT_EQ(vend_id[i], OS2_ACH_VEND_ID[i]);
+  }
+
+  EXPECT_EQ(os2->FsSelection(), OS2_FS_SELECTION);
+  EXPECT_EQ(os2->UsFirstCharIndex(), OS2_US_FIRST_CHAR_IDX);
+  EXPECT_EQ(os2->UsLastCharIndex(), OS2_US_LAST_CHAR_IDX);
+  EXPECT_EQ(os2->STypoAscender(), OS2_STYPO_ASCENDER);
+  EXPECT_EQ(os2->STypoDescender(), OS2_STYPO_DESCENDER);
+  EXPECT_EQ(os2->STypoLineGap(), OS2_STYPO_LINE_GAP);
+  EXPECT_EQ(os2->UsWinAscent(), OS2_US_WIN_ASCENT);
+  EXPECT_EQ(os2->UsWinDescent(), OS2_US_WIN_DESCENT);
+  EXPECT_EQ(os2->UlCodePageRange1(), OS2_UL_CODE_PAGE_RANGE1);
+  EXPECT_EQ(os2->UlCodePageRange2(), OS2_UL_CODE_PAGE_RANGE2);
+
+  // TODO(arthurhsu): SxHeight() not tested
+  // TODO(arthurhsu): SCapHeight() not tested
+  // TODO(arthurhsu): UsDefaultChar() not tested
+  // TODO(arthurhsu): UsBreakChar() not tested
+  // TODO(arthurhsu): UsMaxContext() not tested
+
+  return true;
+}
+
+bool VerifyOS_2(Table* original, Table* target) {
+  EXPECT_TRUE(VerifyOS_2(original));
+  EXPECT_TRUE(VerifyOS_2(target));
+  return true;
+}
+
+}  // namespace sfntly