summaryrefslogtreecommitdiffstats
path: root/gfx/sfntly/cpp/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/sfntly/cpp/src/test')
-rw-r--r--gfx/sfntly/cpp/src/test/autogenerated/cmap_basic_test.cc131
-rw-r--r--gfx/sfntly/cpp/src/test/autogenerated/cmap_test_data.h185
-rw-r--r--gfx/sfntly/cpp/src/test/bitmap_table_test.cc216
-rw-r--r--gfx/sfntly/cpp/src/test/byte_array_test.cc146
-rw-r--r--gfx/sfntly/cpp/src/test/chrome_subsetter.cc75
-rw-r--r--gfx/sfntly/cpp/src/test/cmap_editing_test.cc101
-rw-r--r--gfx/sfntly/cpp/src/test/cmap_iterator_test.cc156
-rw-r--r--gfx/sfntly/cpp/src/test/cmap_test.cc213
-rw-r--r--gfx/sfntly/cpp/src/test/endian_test.cc77
-rw-r--r--gfx/sfntly/cpp/src/test/file_io_test.cc153
-rw-r--r--gfx/sfntly/cpp/src/test/font_data_test.cc337
-rw-r--r--gfx/sfntly/cpp/src/test/font_parsing_test.cc140
-rw-r--r--gfx/sfntly/cpp/src/test/hdmx_test.cc82
-rw-r--r--gfx/sfntly/cpp/src/test/lock_test.cc244
-rwxr-xr-xgfx/sfntly/cpp/src/test/memory_io_test.cc102
-rw-r--r--gfx/sfntly/cpp/src/test/name_editing_test.cc242
-rw-r--r--gfx/sfntly/cpp/src/test/open_type_data_test.cc70
-rw-r--r--gfx/sfntly/cpp/src/test/otf_basic_editing_test.cc101
-rw-r--r--gfx/sfntly/cpp/src/test/platform_thread.cc101
-rw-r--r--gfx/sfntly/cpp/src/test/platform_thread.h75
-rwxr-xr-xgfx/sfntly/cpp/src/test/serialization_test.cc151
-rw-r--r--gfx/sfntly/cpp/src/test/serialization_test.h34
-rw-r--r--gfx/sfntly/cpp/src/test/smart_pointer_test.cc79
-rw-r--r--gfx/sfntly/cpp/src/test/test_data.cc75
-rw-r--r--gfx/sfntly/cpp/src/test/test_data.h44
-rw-r--r--gfx/sfntly/cpp/src/test/test_font_utils.cc115
-rw-r--r--gfx/sfntly/cpp/src/test/test_font_utils.h41
-rw-r--r--gfx/sfntly/cpp/src/test/test_utils.cc89
-rw-r--r--gfx/sfntly/cpp/src/test/test_utils.h110
-rw-r--r--gfx/sfntly/cpp/src/test/test_utils_test.cc84
-rw-r--r--gfx/sfntly/cpp/src/test/test_xml_utils.cc50
-rw-r--r--gfx/sfntly/cpp/src/test/test_xml_utils.h33
-rw-r--r--gfx/sfntly/cpp/src/test/tinyxml/tinystr.cpp111
-rw-r--r--gfx/sfntly/cpp/src/test/tinyxml/tinystr.h305
-rw-r--r--gfx/sfntly/cpp/src/test/tinyxml/tinyxml.cpp1886
-rw-r--r--gfx/sfntly/cpp/src/test/tinyxml/tinyxml.h1805
-rw-r--r--gfx/sfntly/cpp/src/test/tinyxml/tinyxmlerror.cpp52
-rw-r--r--gfx/sfntly/cpp/src/test/tinyxml/tinyxmlparser.cpp1638
-rw-r--r--gfx/sfntly/cpp/src/test/verify_glyf.cc59
-rw-r--r--gfx/sfntly/cpp/src/test/verify_hhea.cc63
-rw-r--r--gfx/sfntly/cpp/src/test/verify_hmtx.cc76
-rw-r--r--gfx/sfntly/cpp/src/test/verify_loca.cc62
-rw-r--r--gfx/sfntly/cpp/src/test/verify_maxp.cc72
-rw-r--r--gfx/sfntly/cpp/src/test/verify_name.cc68
-rw-r--r--gfx/sfntly/cpp/src/test/verify_os2.cc125
45 files changed, 10174 insertions, 0 deletions
diff --git a/gfx/sfntly/cpp/src/test/autogenerated/cmap_basic_test.cc b/gfx/sfntly/cpp/src/test/autogenerated/cmap_basic_test.cc
new file mode 100644
index 0000000000..083b27fa9d
--- /dev/null
+++ b/gfx/sfntly/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, static_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_, static_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, static_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/gfx/sfntly/cpp/src/test/autogenerated/cmap_test_data.h b/gfx/sfntly/cpp/src/test/autogenerated/cmap_test_data.h
new file mode 100644
index 0000000000..4a9f267d1c
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/bitmap_table_test.cc b/gfx/sfntly/cpp/src/test/bitmap_table_test.cc
new file mode 100644
index 0000000000..e9eacc7aac
--- /dev/null
+++ b/gfx/sfntly/cpp/src/test/bitmap_table_test.cc
@@ -0,0 +1,216 @@
+/*
+ * 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);
+
+ if (!bitmap_loca) {
+ return false;
+ }
+
+ EXPECT_EQ(bitmap_loca->NumSizes(), NUM_STRIKES);
+
+ // Strike 1
+ BitmapSizeTablePtr strike1 = bitmap_loca->GetBitmapSizeTable(0);
+ EXPECT_FALSE(strike1 == NULL);
+ if (!strike1) {
+ return false;
+ }
+ 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/gfx/sfntly/cpp/src/test/byte_array_test.cc b/gfx/sfntly/cpp/src/test/byte_array_test.cc
new file mode 100644
index 0000000000..de50089ee2
--- /dev/null
+++ b/gfx/sfntly/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, (uint8_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/gfx/sfntly/cpp/src/test/chrome_subsetter.cc b/gfx/sfntly/cpp/src/test/chrome_subsetter.cc
new file mode 100644
index 0000000000..9563ab1576
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/cmap_editing_test.cc b/gfx/sfntly/cpp/src/test/cmap_editing_test.cc
new file mode 100644
index 0000000000..299b607625
--- /dev/null
+++ b/gfx/sfntly/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, static_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, static_cast<CMapTable::CMap*>(NULL));
+ ASSERT_EQ(CMapTable::WINDOWS_BMP, cmap->cmap_id());
+}
+}
diff --git a/gfx/sfntly/cpp/src/test/cmap_iterator_test.cc b/gfx/sfntly/cpp/src/test/cmap_iterator_test.cc
new file mode 100644
index 0000000000..e01a301628
--- /dev/null
+++ b/gfx/sfntly/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,
+ static_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/gfx/sfntly/cpp/src/test/cmap_test.cc b/gfx/sfntly/cpp/src/test/cmap_test.cc
new file mode 100644
index 0000000000..5961f1cea3
--- /dev/null
+++ b/gfx/sfntly/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, static_cast<FontArray*>(NULL));
+ ASSERT_FALSE(font_array->empty());
+ Ptr<Font> font;
+ font = font_array->at(0);
+ ASSERT_NE(font, static_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_), static_cast<CMapTable::CMap*>(NULL));
+ cmap2_.Attach(cmap_table->GetCMap(GetParam().second_platform_id(),
+ GetParam().second_encoding_id()));
+ ASSERT_NE((cmap2_), static_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/gfx/sfntly/cpp/src/test/endian_test.cc b/gfx/sfntly/cpp/src/test/endian_test.cc
new file mode 100644
index 0000000000..80cce6879a
--- /dev/null
+++ b/gfx/sfntly/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() {
+ uint8_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/gfx/sfntly/cpp/src/test/file_io_test.cc b/gfx/sfntly/cpp/src/test/file_io_test.cc
new file mode 100644
index 0000000000..3cec4d6900
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/font_data_test.cc b/gfx/sfntly/cpp/src/test/font_data_test.cc
new file mode 100644
index 0000000000..5ed041cb69
--- /dev/null
+++ b/gfx/sfntly/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, (uint8_t)(i % 256));
+ }
+}
+
+void ReadFontDataWithSingleByte(ReadableFontData* rfd, ByteVector* buffer) {
+ buffer->resize(rfd->Length());
+ for (int32_t index = 0; index < rfd->Length(); ++index) {
+ (*buffer)[index] = (uint8_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) {
+ uint8_t b = (uint8_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/gfx/sfntly/cpp/src/test/font_parsing_test.cc b/gfx/sfntly/cpp/src/test/font_parsing_test.cc
new file mode 100644
index 0000000000..6fd5c3b29e
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/hdmx_test.cc b/gfx/sfntly/cpp/src/test/hdmx_test.cc
new file mode 100644
index 0000000000..cdc4ed0587
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/lock_test.cc b/gfx/sfntly/cpp/src/test/lock_test.cc
new file mode 100644
index 0000000000..b29a4bf7ab
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/memory_io_test.cc b/gfx/sfntly/cpp/src/test/memory_io_test.cc
new file mode 100755
index 0000000000..b34e1e74f9
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/name_editing_test.cc b/gfx/sfntly/cpp/src/test/name_editing_test.cc
new file mode 100644
index 0000000000..260d9d4ae1
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/open_type_data_test.cc b/gfx/sfntly/cpp/src/test/open_type_data_test.cc
new file mode 100644
index 0000000000..5d73e84d9a
--- /dev/null
+++ b/gfx/sfntly/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 uint8_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(uint8_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] = (uint8_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/gfx/sfntly/cpp/src/test/otf_basic_editing_test.cc b/gfx/sfntly/cpp/src/test/otf_basic_editing_test.cc
new file mode 100644
index 0000000000..04c8778c25
--- /dev/null
+++ b/gfx/sfntly/cpp/src/test/otf_basic_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 "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);
+ if (font_builder_array.size() != 1) {
+ EXPECT_TRUE(false);
+ return false;
+ }
+ FontBuilderPtr font_builder = font_builder_array[0];
+
+ // ensure the builder is not bogus
+ if (!font_builder) {
+ EXPECT_TRUE(false);
+ return false;
+ }
+ TableBuilderMap* builder_map = font_builder->table_builders();
+ if (!builder_map) {
+ EXPECT_TRUE(false);
+ return false;
+ }
+ IntegerSet builder_tags;
+ for (TableBuilderMap::iterator i = builder_map->begin(),
+ e = builder_map->end(); i != e; ++i) {
+ if (!i->second) {
+ EXPECT_TRUE(false);
+ 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);
+ continue;
+ }
+ builder_tags.insert(i->first);
+ }
+
+ FontHeaderTableBuilderPtr header_builder =
+ down_cast<FontHeaderTable::Builder*>(
+ font_builder->GetTableBuilder(Tag::head));
+ int64_t mod_date = header_builder->Modified();
+ EXPECT_EQ(3397043097, mod_date);
+ 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();
+ size_t erased = builder_tags.erase(header->tag());
+ EXPECT_EQ(1U, erased);
+ }
+ 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(TTF_CHECKSUM[SAMPLE_TTF_POST], post->CalculatedChecksum());
+ return true;
+}
+
+} // namespace sfntly
+
+TEST(OTFBasicEditing, All) {
+ ASSERT_TRUE(sfntly::TestOTFBasicEditing());
+}
diff --git a/gfx/sfntly/cpp/src/test/platform_thread.cc b/gfx/sfntly/cpp/src/test/platform_thread.cc
new file mode 100644
index 0000000000..6a0b84b4a7
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/platform_thread.h b/gfx/sfntly/cpp/src/test/platform_thread.h
new file mode 100644
index 0000000000..f236f4cdf3
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/serialization_test.cc b/gfx/sfntly/cpp/src/test/serialization_test.cc
new file mode 100755
index 0000000000..0f2f489f4b
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/serialization_test.h b/gfx/sfntly/cpp/src/test/serialization_test.h
new file mode 100644
index 0000000000..8996793585
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/smart_pointer_test.cc b/gfx/sfntly/cpp/src/test/smart_pointer_test.cc
new file mode 100644
index 0000000000..9e81baaba6
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/test_data.cc b/gfx/sfntly/cpp/src/test/test_data.cc
new file mode 100644
index 0000000000..05bc7595e0
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/test_data.h b/gfx/sfntly/cpp/src/test/test_data.h
new file mode 100644
index 0000000000..d5e576fa0d
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/test_font_utils.cc b/gfx/sfntly/cpp/src/test/test_font_utils.cc
new file mode 100644
index 0000000000..a00a811d6c
--- /dev/null
+++ b/gfx/sfntly/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, static_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, static_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/gfx/sfntly/cpp/src/test/test_font_utils.h b/gfx/sfntly/cpp/src/test/test_font_utils.h
new file mode 100644
index 0000000000..57fde7a658
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/test_utils.cc b/gfx/sfntly/cpp/src/test/test_utils.cc
new file mode 100644
index 0000000000..4751b92625
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/test_utils.h b/gfx/sfntly/cpp/src/test/test_utils.h
new file mode 100644
index 0000000000..af3ffd6c83
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/test_utils_test.cc b/gfx/sfntly/cpp/src/test/test_utils_test.cc
new file mode 100644
index 0000000000..fbd5ed1a28
--- /dev/null
+++ b/gfx/sfntly/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) {
+ uint8_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/gfx/sfntly/cpp/src/test/test_xml_utils.cc b/gfx/sfntly/cpp/src/test/test_xml_utils.cc
new file mode 100644
index 0000000000..dc65add747
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/test_xml_utils.h b/gfx/sfntly/cpp/src/test/test_xml_utils.h
new file mode 100644
index 0000000000..7a5fe49d6b
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/tinyxml/tinystr.cpp b/gfx/sfntly/cpp/src/test/tinyxml/tinystr.cpp
new file mode 100644
index 0000000000..0665768205
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/tinyxml/tinystr.h b/gfx/sfntly/cpp/src/test/tinyxml/tinystr.h
new file mode 100644
index 0000000000..89cca33415
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/tinyxml/tinyxml.cpp b/gfx/sfntly/cpp/src/test/tinyxml/tinyxml.cpp
new file mode 100644
index 0000000000..9c161dfcb9
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/tinyxml/tinyxml.h b/gfx/sfntly/cpp/src/test/tinyxml/tinyxml.h
new file mode 100644
index 0000000000..a3589e5b26
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/tinyxml/tinyxmlerror.cpp b/gfx/sfntly/cpp/src/test/tinyxml/tinyxmlerror.cpp
new file mode 100644
index 0000000000..538c21d0bd
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/tinyxml/tinyxmlparser.cpp b/gfx/sfntly/cpp/src/test/tinyxml/tinyxmlparser.cpp
new file mode 100644
index 0000000000..81b7eae96b
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/verify_glyf.cc b/gfx/sfntly/cpp/src/test/verify_glyf.cc
new file mode 100644
index 0000000000..abfe1ab8aa
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/verify_hhea.cc b/gfx/sfntly/cpp/src/test/verify_hhea.cc
new file mode 100644
index 0000000000..1e1001cd66
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/verify_hmtx.cc b/gfx/sfntly/cpp/src/test/verify_hmtx.cc
new file mode 100644
index 0000000000..d37bba98b2
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/verify_loca.cc b/gfx/sfntly/cpp/src/test/verify_loca.cc
new file mode 100644
index 0000000000..4a32928875
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/verify_maxp.cc b/gfx/sfntly/cpp/src/test/verify_maxp.cc
new file mode 100644
index 0000000000..074042a0b9
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/verify_name.cc b/gfx/sfntly/cpp/src/test/verify_name.cc
new file mode 100644
index 0000000000..e1101c078f
--- /dev/null
+++ b/gfx/sfntly/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/gfx/sfntly/cpp/src/test/verify_os2.cc b/gfx/sfntly/cpp/src/test/verify_os2.cc
new file mode 100644
index 0000000000..c80c58a8f5
--- /dev/null
+++ b/gfx/sfntly/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 uint8_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 uint8_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