diff -Nru simgear-2.10.0/3rdparty/CMakeLists.txt simgear-3.0.0/3rdparty/CMakeLists.txt --- simgear-2.10.0/3rdparty/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,4 @@ +if (NOT SYSTEM_EXPAT) + add_subdirectory(expat) +endif() + diff -Nru simgear-2.10.0/3rdparty/expat/ascii.h simgear-3.0.0/3rdparty/expat/ascii.h --- simgear-2.10.0/3rdparty/expat/ascii.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/ascii.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,92 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#define ASCII_A 0x41 +#define ASCII_B 0x42 +#define ASCII_C 0x43 +#define ASCII_D 0x44 +#define ASCII_E 0x45 +#define ASCII_F 0x46 +#define ASCII_G 0x47 +#define ASCII_H 0x48 +#define ASCII_I 0x49 +#define ASCII_J 0x4A +#define ASCII_K 0x4B +#define ASCII_L 0x4C +#define ASCII_M 0x4D +#define ASCII_N 0x4E +#define ASCII_O 0x4F +#define ASCII_P 0x50 +#define ASCII_Q 0x51 +#define ASCII_R 0x52 +#define ASCII_S 0x53 +#define ASCII_T 0x54 +#define ASCII_U 0x55 +#define ASCII_V 0x56 +#define ASCII_W 0x57 +#define ASCII_X 0x58 +#define ASCII_Y 0x59 +#define ASCII_Z 0x5A + +#define ASCII_a 0x61 +#define ASCII_b 0x62 +#define ASCII_c 0x63 +#define ASCII_d 0x64 +#define ASCII_e 0x65 +#define ASCII_f 0x66 +#define ASCII_g 0x67 +#define ASCII_h 0x68 +#define ASCII_i 0x69 +#define ASCII_j 0x6A +#define ASCII_k 0x6B +#define ASCII_l 0x6C +#define ASCII_m 0x6D +#define ASCII_n 0x6E +#define ASCII_o 0x6F +#define ASCII_p 0x70 +#define ASCII_q 0x71 +#define ASCII_r 0x72 +#define ASCII_s 0x73 +#define ASCII_t 0x74 +#define ASCII_u 0x75 +#define ASCII_v 0x76 +#define ASCII_w 0x77 +#define ASCII_x 0x78 +#define ASCII_y 0x79 +#define ASCII_z 0x7A + +#define ASCII_0 0x30 +#define ASCII_1 0x31 +#define ASCII_2 0x32 +#define ASCII_3 0x33 +#define ASCII_4 0x34 +#define ASCII_5 0x35 +#define ASCII_6 0x36 +#define ASCII_7 0x37 +#define ASCII_8 0x38 +#define ASCII_9 0x39 + +#define ASCII_TAB 0x09 +#define ASCII_SPACE 0x20 +#define ASCII_EXCL 0x21 +#define ASCII_QUOT 0x22 +#define ASCII_AMP 0x26 +#define ASCII_APOS 0x27 +#define ASCII_MINUS 0x2D +#define ASCII_PERIOD 0x2E +#define ASCII_COLON 0x3A +#define ASCII_SEMI 0x3B +#define ASCII_LT 0x3C +#define ASCII_EQUALS 0x3D +#define ASCII_GT 0x3E +#define ASCII_LSQB 0x5B +#define ASCII_RSQB 0x5D +#define ASCII_UNDERSCORE 0x5F +#define ASCII_LPAREN 0x28 +#define ASCII_RPAREN 0x29 +#define ASCII_FF 0x0C +#define ASCII_SLASH 0x2F +#define ASCII_HASH 0x23 +#define ASCII_PIPE 0x7C +#define ASCII_COMMA 0x2C diff -Nru simgear-2.10.0/3rdparty/expat/asciitab.h simgear-3.0.0/3rdparty/expat/asciitab.h --- simgear-2.10.0/3rdparty/expat/asciitab.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/asciitab.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,62 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (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.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff -Nru simgear-2.10.0/3rdparty/expat/CMakeLists.txt simgear-3.0.0/3rdparty/expat/CMakeLists.txt --- simgear-2.10.0/3rdparty/expat/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,33 @@ + +configure_file ( + "${PROJECT_SOURCE_DIR}/3rdparty/expat/expat_config_cmake.in" + "${PROJECT_BINARY_DIR}/3rdparty/expat/expat_config.h" +) + +set(expat_sources + asciitab.h + hashtable.h + iasciitab.h + latin1tab.h + nametab.h + utf8tab.h + xmldef.h + xmlparse.h + xmlrole.h + xmltok.h + xmltok_impl.h + hashtable.c + xmlparse.c + xmlrole.c + xmltok.c + internal.h + ascii.h + sg_expat.h + sg_expat_external.h + ) + +foreach(s ${expat_sources}) + set_property(GLOBAL + APPEND PROPERTY LOCAL_EXPAT_SOURCES + "${CMAKE_CURRENT_SOURCE_DIR}/${s}") +endforeach() diff -Nru simgear-2.10.0/3rdparty/expat/expat_config_cmake.in simgear-3.0.0/3rdparty/expat/expat_config_cmake.in --- simgear-2.10.0/3rdparty/expat/expat_config_cmake.in 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/expat_config_cmake.in 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,41 @@ + +#ifndef EXPAT_CONFIG_H +#define EXPAT_CONFIG_H + +#cmakedefine HAVE_WINDOWS_H + +#ifdef HAVE_WINDOWS_H + #define WIN32_LEAN_AND_MEAN + #include + #undef WIN32_LEAN_AND_MEAN +#endif + +/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ +#define BYTEORDER 1234 + +/* Define to 1 if you have the `bcopy' function. */ +#cmakedefine HAVE_BCOPY + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE + +/* Define to 1 if you have a working `mmap' system call. */ +#cmakedefine HAVE_MMAP + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H + +/* whether byteorder is bigendian */ +#undef WORDS_BIGENDIAN + +/* Define to specify how much context to retain around the current parse + point. */ +#define XML_CONTEXT_BYTES 1024 + +/* Define to make parameter entity parsing functionality available. */ +#define XML_DTD + +/* Define to make XML Namespaces functionality available. */ +#define XML_NS + +#endif /* ifndef EXPAT_CONFIG_H */ diff -Nru simgear-2.10.0/3rdparty/expat/Expat.COPYING simgear-3.0.0/3rdparty/expat/Expat.COPYING --- simgear-2.10.0/3rdparty/expat/Expat.COPYING 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/Expat.COPYING 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,22 @@ +Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + and Clark Cooper +Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff -Nru simgear-2.10.0/3rdparty/expat/hashtable.c simgear-3.0.0/3rdparty/expat/hashtable.c --- simgear-2.10.0/3rdparty/expat/hashtable.c 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/hashtable.c 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,151 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (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.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + +#include "xmldef.h" + +#ifdef XML_UNICODE_WCHAR_T +#ifndef XML_UNICODE +#define XML_UNICODE +#endif +#endif + +#include "hashtable.h" + +#define INIT_SIZE 64 + +static +int keyeq(KEY s1, KEY s2) +{ + for (; *s1 == *s2; s1++, s2++) + if (*s1 == 0) + return 1; + return 0; +} + +static +unsigned long hash(KEY s) +{ + unsigned long h = 0; + while (*s) + h = (h << 5) + h + (unsigned char)*s++; + return h; +} + +NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize) +{ + size_t i; + if (table->size == 0) { + if (!createSize) + return 0; + table->v = calloc(INIT_SIZE, sizeof(NAMED *)); + if (!table->v) + return 0; + table->size = INIT_SIZE; + table->usedLim = INIT_SIZE / 2; + i = hash(name) & (table->size - 1); + } + else { + unsigned long h = hash(name); + for (i = h & (table->size - 1); + table->v[i]; + i == 0 ? i = table->size - 1 : --i) { + if (keyeq(name, table->v[i]->name)) + return table->v[i]; + } + if (!createSize) + return 0; + if (table->used == table->usedLim) { + /* check for overflow */ + size_t newSize = table->size * 2; + NAMED **newV = calloc(newSize, sizeof(NAMED *)); + if (!newV) + return 0; + for (i = 0; i < table->size; i++) + if (table->v[i]) { + size_t j; + for (j = hash(table->v[i]->name) & (newSize - 1); + newV[j]; + j == 0 ? j = newSize - 1 : --j) + ; + newV[j] = table->v[i]; + } + free(table->v); + table->v = newV; + table->size = newSize; + table->usedLim = newSize/2; + for (i = h & (table->size - 1); + table->v[i]; + i == 0 ? i = table->size - 1 : --i) + ; + } + } + table->v[i] = calloc(1, createSize); + if (!table->v[i]) + return 0; + table->v[i]->name = name; + (table->used)++; + return table->v[i]; +} + +void hashTableDestroy(HASH_TABLE *table) +{ + size_t i; + for (i = 0; i < table->size; i++) { + NAMED *p = table->v[i]; + if (p) + free(p); + } + free(table->v); +} + +void hashTableInit(HASH_TABLE *p) +{ + p->size = 0; + p->usedLim = 0; + p->used = 0; + p->v = 0; +} + +void hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) +{ + iter->p = table->v; + iter->end = iter->p + table->size; +} + +NAMED *hashTableIterNext(HASH_TABLE_ITER *iter) +{ + while (iter->p != iter->end) { + NAMED *tem = *(iter->p)++; + if (tem) + return tem; + } + return 0; +} + diff -Nru simgear-2.10.0/3rdparty/expat/hashtable.h simgear-3.0.0/3rdparty/expat/hashtable.h --- simgear-2.10.0/3rdparty/expat/hashtable.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/hashtable.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,69 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (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.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + + +#include + +#ifdef XML_UNICODE + +#ifdef XML_UNICODE_WCHAR_T +typedef const wchar_t *KEY; +#else /* not XML_UNICODE_WCHAR_T */ +typedef const unsigned short *KEY; +#endif /* not XML_UNICODE_WCHAR_T */ + +#else /* not XML_UNICODE */ + +typedef const char *KEY; + +#endif /* not XML_UNICODE */ + +typedef struct { + KEY name; +} NAMED; + +typedef struct { + NAMED **v; + size_t size; + size_t used; + size_t usedLim; +} HASH_TABLE; + +NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize); +void hashTableInit(HASH_TABLE *); +void hashTableDestroy(HASH_TABLE *); + +typedef struct { + NAMED **p; + NAMED **end; +} HASH_TABLE_ITER; + +void hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); +NAMED *hashTableIterNext(HASH_TABLE_ITER *); diff -Nru simgear-2.10.0/3rdparty/expat/iasciitab.h simgear-3.0.0/3rdparty/expat/iasciitab.h --- simgear-2.10.0/3rdparty/expat/iasciitab.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/iasciitab.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,63 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (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.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + +/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */ +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff -Nru simgear-2.10.0/3rdparty/expat/internal.h simgear-3.0.0/3rdparty/expat/internal.h --- simgear-2.10.0/3rdparty/expat/internal.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/internal.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,73 @@ +/* internal.h + + Internal definitions used by Expat. This is not needed to compile + client code. + + The following calling convention macros are defined for frequently + called functions: + + FASTCALL - Used for those internal functions that have a simple + body and a low number of arguments and local variables. + + PTRCALL - Used for functions called though function pointers. + + PTRFASTCALL - Like PTRCALL, but for low number of arguments. + + inline - Used for selected internal functions for which inlining + may improve performance on some platforms. + + Note: Use of these macros is based on judgement, not hard rules, + and therefore subject to change. +*/ + +#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__) +/* We'll use this version by default only where we know it helps. + + regparm() generates warnings on Solaris boxes. See SF bug #692878. + + Instability reported with egcs on a RedHat Linux 7.3. + Let's comment out: + #define FASTCALL __attribute__((stdcall, regparm(3))) + and let's try this: +*/ +#define FASTCALL __attribute__((regparm(3))) +#define PTRFASTCALL __attribute__((regparm(3))) +#endif + +/* Using __fastcall seems to have an unexpected negative effect under + MS VC++, especially for function pointers, so we won't use it for + now on that platform. It may be reconsidered for a future release + if it can be made more effective. + Likely reason: __fastcall on Windows is like stdcall, therefore + the compiler cannot perform stack optimizations for call clusters. +*/ + +/* Make sure all of these are defined if they aren't already. */ + +#ifndef FASTCALL +#define FASTCALL +#endif + +#ifndef PTRCALL +#define PTRCALL +#endif + +#ifndef PTRFASTCALL +#define PTRFASTCALL +#endif + +#ifndef XML_MIN_SIZE +#if !defined(__cplusplus) && !defined(inline) +#ifdef __GNUC__ +#define inline __inline +#endif /* __GNUC__ */ +#endif +#endif /* XML_MIN_SIZE */ + +#ifdef __cplusplus +#define inline inline +#else +#ifndef inline +#define inline +#endif +#endif diff -Nru simgear-2.10.0/3rdparty/expat/latin1tab.h simgear-3.0.0/3rdparty/expat/latin1tab.h --- simgear-2.10.0/3rdparty/expat/latin1tab.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/latin1tab.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,62 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (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.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + +/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME, +/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, diff -Nru simgear-2.10.0/3rdparty/expat/nametab.h simgear-3.0.0/3rdparty/expat/nametab.h --- simgear-2.10.0/3rdparty/expat/nametab.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/nametab.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,150 @@ +static const unsigned namingBitmap[] = { +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE, +0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF, +0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF, +0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, +0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000, +0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060, +0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, +0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003, +0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000, +0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, +0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003, +0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000, +0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, +0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003, +0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000, +0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000, +0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, +0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB, +0x40000000, 0xF580C900, 0x00000007, 0x02010800, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF, +0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF, +0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, +0x00000000, 0x00004C40, 0x00000000, 0x00000000, +0x00000007, 0x00000000, 0x00000000, 0x00000000, +0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, +0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF, +0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000, +0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE, +0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, +0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, +0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF, +0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, +0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF, +0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF, +0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, +0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0, +0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1, +0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, +0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80, +0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3, +0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, +0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, +0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000, +0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF, +0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x1FFF0000, 0x00000002, +0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, +0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF, +}; +static const unsigned char nmstrtPages[] = { +0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, +0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, +0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const unsigned char namePages[] = { +0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, +0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, +0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff -Nru simgear-2.10.0/3rdparty/expat/sg_expat_external.h simgear-3.0.0/3rdparty/expat/sg_expat_external.h --- simgear-2.10.0/3rdparty/expat/sg_expat_external.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/sg_expat_external.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,115 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef Expat_External_INCLUDED +#define Expat_External_INCLUDED 1 + +/* External API definitions */ + +#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__) +#define XML_USE_MSC_EXTENSIONS 1 +#endif + +/* Expat tries very hard to make the API boundary very specifically + defined. There are two macros defined to control this boundary; + each of these can be defined before including this header to + achieve some different behavior, but doing so it not recommended or + tested frequently. + + XMLCALL - The calling convention to use for all calls across the + "library boundary." This will default to cdecl, and + try really hard to tell the compiler that's what we + want. + + XMLIMPORT - Whatever magic is needed to note that a function is + to be imported from a dynamically loaded library + (.dll, .so, or .sl, depending on your platform). + + The XMLCALL macro was added in Expat 1.95.7. The only one which is + expected to be directly useful in client code is XMLCALL. + + Note that on at least some Unix versions, the Expat library must be + compiled with the cdecl calling convention as the default since + system headers may assume the cdecl convention. +*/ +#ifndef XMLCALL +#if defined(_MSC_VER) +#define XMLCALL __cdecl +#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER) +#define XMLCALL __attribute__((cdecl)) +#else +/* For any platform which uses this definition and supports more than + one calling convention, we need to extend this definition to + declare the convention used on that platform, if it's possible to + do so. + + If this is the case for your platform, please file a bug report + with information on how to identify your platform via the C + pre-processor and how to specify the same calling convention as the + platform's malloc() implementation. +*/ +#define XMLCALL +#endif +#endif /* not defined XMLCALL */ + + +#if !defined(XML_STATIC) && !defined(XMLIMPORT) +#ifndef XML_BUILDING_EXPAT +/* using Expat from an application */ + +#ifdef XML_USE_MSC_EXTENSIONS +#define XMLIMPORT __declspec(dllimport) +#endif + +#endif +#endif /* not defined XML_STATIC */ + + +/* If we didn't define it above, define it away: */ +#ifndef XMLIMPORT +#define XMLIMPORT +#endif + + +#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef XML_UNICODE_WCHAR_T +#define XML_UNICODE +#endif + +#ifdef XML_UNICODE /* Information is UTF-16 encoded. */ +#ifdef XML_UNICODE_WCHAR_T +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; +#else +typedef unsigned short XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE_WCHAR_T */ +#else /* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE */ + +#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */ +#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400 +typedef __int64 XML_Index; +typedef unsigned __int64 XML_Size; +#else +typedef long long XML_Index; +typedef unsigned long long XML_Size; +#endif +#else +typedef long XML_Index; +typedef unsigned long XML_Size; +#endif /* XML_LARGE_SIZE */ + +#ifdef __cplusplus +} +#endif + +#endif /* not Expat_External_INCLUDED */ diff -Nru simgear-2.10.0/3rdparty/expat/sg_expat.h simgear-3.0.0/3rdparty/expat/sg_expat.h --- simgear-2.10.0/3rdparty/expat/sg_expat.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/sg_expat.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,1047 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef Expat_INCLUDED +#define Expat_INCLUDED 1 + +#ifdef __VMS +/* 0 1 2 3 0 1 2 3 + 1234567890123456789012345678901 1234567890123456789012345678901 */ +#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler +#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler +#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler +#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg +#endif + +#include +#include "sg_expat_external.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct XML_ParserStruct; +typedef struct XML_ParserStruct *XML_Parser; + +/* Should this be defined using stdbool.h when C99 is available? */ +typedef unsigned char XML_Bool; +#define XML_TRUE ((XML_Bool) 1) +#define XML_FALSE ((XML_Bool) 0) + +/* The XML_Status enum gives the possible return values for several + API functions. The preprocessor #defines are included so this + stanza can be added to code that still needs to support older + versions of Expat 1.95.x: + + #ifndef XML_STATUS_OK + #define XML_STATUS_OK 1 + #define XML_STATUS_ERROR 0 + #endif + + Otherwise, the #define hackery is quite ugly and would have been + dropped. +*/ +enum XML_Status { + XML_STATUS_ERROR = 0, +#define XML_STATUS_ERROR XML_STATUS_ERROR + XML_STATUS_OK = 1, +#define XML_STATUS_OK XML_STATUS_OK + XML_STATUS_SUSPENDED = 2 +#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED +}; + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE, + XML_ERROR_ENTITY_DECLARED_IN_PE, + XML_ERROR_FEATURE_REQUIRES_XML_DTD, + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING, + /* Added in 1.95.7. */ + XML_ERROR_UNBOUND_PREFIX, + /* Added in 1.95.8. */ + XML_ERROR_UNDECLARING_PREFIX, + XML_ERROR_INCOMPLETE_PE, + XML_ERROR_XML_DECL, + XML_ERROR_TEXT_DECL, + XML_ERROR_PUBLICID, + XML_ERROR_SUSPENDED, + XML_ERROR_NOT_SUSPENDED, + XML_ERROR_ABORTED, + XML_ERROR_FINISHED, + XML_ERROR_SUSPEND_PE, + /* Added in 2.0. */ + XML_ERROR_RESERVED_PREFIX_XML, + XML_ERROR_RESERVED_PREFIX_XMLNS, + XML_ERROR_RESERVED_NAMESPACE_URI +}; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + XML_Char * name; + unsigned int numchildren; + XML_Content * children; +}; + + +/* This is called for an element declaration. See above for + description of the model argument. It's the caller's responsibility + to free model when finished with it. +*/ +typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData, + const XML_Char *name, + XML_Content *model); + +XMLPARSEAPI(void) +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl); + +/* The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" + keyword. The "isrequired" parameter will be true and the default + value will be NULL in the case of "#REQUIRED". If "isrequired" is + true and default is non-NULL, then this is a "#FIXED" default. +*/ +typedef void (XMLCALL *XML_AttlistDeclHandler) ( + void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired); + +XMLPARSEAPI(void) +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl); + +/* The XML declaration handler is called for *both* XML declarations + and text declarations. The way to distinguish is that the version + parameter will be NULL for text declarations. The encoding + parameter may be NULL for XML declarations. The standalone + parameter will be -1, 0, or 1 indicating respectively that there + was no standalone parameter in the declaration, that it was given + as no, or that it was given as yes. +*/ +typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +XMLPARSEAPI(void) +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler xmldecl); + + +typedef struct { + void *(*malloc_fcn)(size_t size); + void *(*realloc_fcn)(void *ptr, size_t size); + void (*free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the + external protocol or NULL if there is none specified. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type + names and attribute names that belong to a namespace will be + expanded; unprefixed attribute names are never expanded; unprefixed + element type names are expanded only if there is a default + namespace. The expanded name is the concatenation of the namespace + URI, the namespace separator character, and the local part of the + name. If the namespace separator is '\0' then the namespace URI + and the local part will be concatenated without any separator. + It is a programming error to use the separator '\0' with namespace + triplets (see XML_SetReturnNSTriplet). +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* Constructs a new parser using the memory management suite referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* Prepare a parser object to be re-used. This is particularly + valuable when memory allocation overhead is disproportionatly high, + such as when a large number of small documnents need to be parsed. + All handlers are cleared from the parser, except for the + unknownEncodingHandler. The parser's external state is re-initialized + except for the values of ns and ns_triplets. + + Added in Expat 1.95.3. +*/ +XMLPARSEAPI(XML_Bool) +XML_ParserReset(XML_Parser parser, const XML_Char *encoding); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. +*/ +typedef void (XMLCALL *XML_StartElementHandler) (void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (XMLCALL *XML_EndElementHandler) (void *userData, + const XML_Char *name); + + +/* s is not 0 terminated. */ +typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (XMLCALL *XML_ProcessingInstructionHandler) ( + void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (XMLCALL *XML_CommentHandler) (void *userData, + const XML_Char *data); + +typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData); +typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData); + +/* This is called for any characters in the XML document for which + there is no applicable handler. This includes both characters that + are part of markup which is of a kind that is not reported + (comments, markup declarations), or characters that are part of a + construct which could be reported but for which no handler has been + supplied. The characters are passed exactly as they were in the XML + document except that they will be encoded in UTF-8 or UTF-16. + Line boundaries are not normalized. Note that a byte order mark + character is not passed to the default handler. There are no + guarantees about how characters are divided between calls to the + default handler: for example, a comment might be split between + multiple calls. +*/ +typedef void (XMLCALL *XML_DefaultHandler) (void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. +*/ +typedef void (XMLCALL *XML_StartDoctypeDeclHandler) ( + void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset); + +/* This is called for the start of the DOCTYPE declaration when the + closing > is encountered, but after processing any external + subset. +*/ +typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (), value will + be non-NULL and systemId, publicID, and notationName will be NULL. + The value string is NOT nul-terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be NULL and systemId will be + non-NULL. The publicId argument will be NULL unless a public + identifier was provided. The notationName argument will have a + non-NULL value only for unparsed entity declarations. + + Note that is_parameter_entity can't be changed to XML_Bool, since + that would break binary compatibility. +*/ +typedef void (XMLCALL *XML_EntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +XMLPARSEAPI(void) +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superceded by the EntityDeclHandler above. + It is provided here for backward compatibility. + + This is called for a declaration of an unparsed (NDATA) entity. + The base argument is whatever was set by XML_SetBase. The + entityName, systemId and notationName arguments will never be + NULL. The other arguments may be. +*/ +typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. The base argument is + whatever was set by XML_SetBase. The notationName will never be + NULL. The other arguments can be. +*/ +typedef void (XMLCALL *XML_NotationDeclHandler) ( + void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for + each namespace declaration. The call to the start and end element + handlers occur between the calls to the start and end namespace + declaration handlers. For an xmlns attribute, prefix will be + NULL. For an xmlns="" attribute, uri will be NULL. +*/ +typedef void (XMLCALL *XML_StartNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (XMLCALL *XML_EndNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone, that is, it has an + external subset or a reference to a parameter entity, but does not + have standalone="yes". If this handler returns XML_STATUS_ERROR, + then processing will not continue, and the parser will return a + XML_ERROR_NOT_STANDALONE error. + If parameter entity parsing is enabled, then in addition to the + conditions above this handler will only be called if the referenced + entity was actually read. +*/ +typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData); + +/* This is called for a reference to an external parsed general + entity. The referenced entity is not automatically parsed. The + application can parse it immediately or later using + XML_ExternalEntityParserCreate. + + The parser argument is the parser parsing the entity containing the + reference; it can be passed as the parser argument to + XML_ExternalEntityParserCreate. The systemId argument is the + system identifier as specified in the entity declaration; it will + not be NULL. + + The base argument is the system identifier that should be used as + the base for resolving systemId if systemId was relative; this is + set by XML_SetBase; it may be NULL. + + The publicId argument is the public identifier as specified in the + entity declaration, or NULL if none was specified; the whitespace + in the public identifier will have been normalized as required by + the XML spec. + + The context argument specifies the parsing context in the format + expected by the context argument to XML_ExternalEntityParserCreate; + context is valid only until the handler returns, so if the + referenced entity is to be parsed later, it must be copied. + context is NULL only when the entity is a parameter entity. + + The handler should return XML_STATUS_ERROR if processing should not + continue because of a fatal error in the handling of the external + entity. In this case the calling parser will return an + XML_ERROR_EXTERNAL_ENTITY_HANDLING error. + + Note that unlike other handlers the first argument is the parser, + not userData. +*/ +typedef int (XMLCALL *XML_ExternalEntityRefHandler) ( + XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This is called in two situations: + 1) An entity reference is encountered for which no declaration + has been read *and* this is not an error. + 2) An internal entity reference is read, but not expanded, because + XML_SetDefaultHandler has been called. + Note: skipped parameter entities in declarations and skipped general + entities in attribute values cannot be reported, because + the event would be out of sync with the reporting of the + declarations or attribute values +*/ +typedef void (XMLCALL *XML_SkippedEntityHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity); + +/* This structure is filled in by the XML_UnknownEncodingHandler to + provide information to the parser about encodings that are unknown + to the parser. + + The map[b] member gives information about byte sequences whose + first byte is b. + + If map[b] is c where c is >= 0, then b by itself encodes the + Unicode scalar value c. + + If map[b] is -1, then the byte sequence is malformed. + + If map[b] is -n, where n >= 2, then b is the first byte of an + n-byte sequence that encodes a single Unicode scalar value. + + The data member will be passed as the first argument to the convert + function. + + The convert function is used to convert multibyte sequences; s will + point to a n-byte sequence where map[(unsigned char)*s] == -n. The + convert function must return the Unicode scalar value represented + by this byte sequence or -1 if the byte sequence is malformed. + + The convert function may be NULL if the encoding is a single-byte + encoding, that is if map[b] >= -1 for all bytes b. + + When the parser is finished with the encoding, then if release is + not NULL, it will call release passing it the data member; once + release has been called, the convert function will not be called + again. + + Expat places certain restrictions on the encodings that are supported + using this mechanism. + + 1. Every ASCII character that can appear in a well-formed XML document, + other than the characters + + $@\^`{}~ + + must be represented by a single byte, and that byte must be the + same byte that represents that character in ASCII. + + 2. No character may require more than 4 bytes to encode. + + 3. All characters encoded must have Unicode scalar values <= + 0xFFFF, (i.e., characters that would be encoded by surrogates in + UTF-16 are not allowed). Note that this restriction doesn't + apply to the built-in support for UTF-8 and UTF-16. + + 4. No Unicode character may be encoded by more than one distinct + sequence of bytes. +*/ +typedef struct { + int map[256]; + void *data; + int (XMLCALL *convert)(void *data, const char *s); + void (XMLCALL *release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. + + The encodingHandlerData argument is that which was passed as the + second argument to XML_SetUnknownEncodingHandler. + + The name argument gives the name of the encoding as specified in + the encoding declaration. + + If the callback can provide information about the encoding, it must + fill in the XML_Encoding structure, and return XML_STATUS_OK. + Otherwise it must return XML_STATUS_ERROR. + + If info does not describe a suitable encoding, then the parser will + return an XML_UNKNOWN_ENCODING error. +*/ +typedef int (XMLCALL *XML_UnknownEncodingHandler) ( + void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +XMLPARSEAPI(void) +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +XMLPARSEAPI(void) +XML_SetStartElementHandler(XML_Parser parser, + XML_StartElementHandler handler); + +XMLPARSEAPI(void) +XML_SetEndElementHandler(XML_Parser parser, + XML_EndElementHandler handler); + +XMLPARSEAPI(void) +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +XMLPARSEAPI(void) +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +XMLPARSEAPI(void) +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +XMLPARSEAPI(void) +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +XMLPARSEAPI(void) +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +XMLPARSEAPI(void) +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of + internal entities. These entity references will be passed to the + default handler, or to the skipped entity handler, if one is set. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of + internal entities. The entity reference will not be passed to the + default handler. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +XMLPARSEAPI(void) +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-NULL value for arg is specified here, then it will be + passed as the first argument to the external entity ref handler + instead of the parser object. +*/ +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandlerArg(XML_Parser parser, + void *arg); + +XMLPARSEAPI(void) +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler); + +XMLPARSEAPI(void) +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end + element, processing instruction or character data. It causes the + corresponding markup to be passed to the default handler. +*/ +XMLPARSEAPI(void) +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single string separated by + the separator character specified when the parser was created: URI + + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the name + has a prefix. + + Note: Calling XML_SetReturnNSTriplet after XML_Parse or + XML_ParseBuffer has no effect. +*/ + +XMLPARSEAPI(void) +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +XMLPARSEAPI(void) +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or NULL. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument to + XML_ParserCreate. On success XML_SetEncoding returns non-zero, + zero otherwise. + Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer + has no effect and returns XML_STATUS_ERROR. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed as the + first argument to callbacks instead of userData. The userData will + still be accessible using XML_GetUserData. +*/ +XMLPARSEAPI(void) +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* If useDTD == XML_TRUE is passed to this function, then the parser + will assume that there is an external subset, even if none is + specified in the document. In such a case the parser will call the + externalEntityRefHandler with a value of NULL for the systemId + argument (the publicId and context arguments will be NULL as well). + Note: For the purpose of checking WFC: Entity Declared, passing + useDTD == XML_TRUE will make the parser behave as if the document + had a DTD with an external subset. + Note: If this function is called, then this must be done before + the first call to XML_Parse or XML_ParseBuffer, since it will + have no effect after that. Returns + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING. + Note: If the document does not have a DOCTYPE declaration at all, + then startDoctypeDeclHandler and endDoctypeDeclHandler will not + be called, despite an external subset being parsed. + Note: If XML_DTD is not defined when Expat is compiled, returns + XML_ERROR_FEATURE_REQUIRES_XML_DTD. +*/ +XMLPARSEAPI(enum XML_Error) +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD); + + +/* Sets the base to be used for resolving relative URIs in system + identifiers in declarations. Resolving relative identifiers is + left to the application: this value will be passed through as the + base argument to the XML_ExternalEntityRefHandler, + XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base + argument will be copied. Returns XML_STATUS_ERROR if out of memory, + XML_STATUS_OK otherwise. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetBase(XML_Parser parser, const XML_Char *base); + +XMLPARSEAPI(const XML_Char *) +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call + to the XML_StartElementHandler that were specified in the start-tag + rather than defaulted. Each attribute/value pair counts as 2; thus + this correspondds to an index into the atts array passed to the + XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to + XML_StartElementHandler, or -1 if there is no ID attribute. Each + attribute/value pair counts as 2; thus this correspondds to an + index into the atts array passed to the XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetIdAttributeIndex(XML_Parser parser); + +#ifdef XML_ATTR_INFO +/* Source file byte offsets for the start and end of attribute names and values. + The value indices are exclusive of surrounding quotes; thus in a UTF-8 source + file an attribute value of "blah" will yield: + info->valueEnd - info->valueStart = 4 bytes. +*/ +typedef struct { + XML_Index nameStart; /* Offset to beginning of the attribute name. */ + XML_Index nameEnd; /* Offset after the attribute name's last byte. */ + XML_Index valueStart; /* Offset to beginning of the attribute value. */ + XML_Index valueEnd; /* Offset after the attribute value's last byte. */ +} XML_AttrInfo; + +/* Returns an array of XML_AttrInfo structures for the attribute/value pairs + passed in last call to the XML_StartElementHandler that were specified + in the start-tag rather than defaulted. Each attribute/value pair counts + as 1; thus the number of entries in the array is + XML_GetSpecifiedAttributeCount(parser) / 2. +*/ +XMLPARSEAPI(const XML_AttrInfo *) +XML_GetAttributeInfo(XML_Parser parser); +#endif + +/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is + detected. The last call to XML_Parse must have isFinal true; len + may be zero for this call (or any other). + + Though the return values for these functions has always been + described as a Boolean value, the implementation, at least for the + 1.95.x series, has always returned exactly one of the XML_Status + values. +*/ +XMLPARSEAPI(enum XML_Status) +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +XMLPARSEAPI(void *) +XML_GetBuffer(XML_Parser parser, int len); + +XMLPARSEAPI(enum XML_Status) +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return. + Must be called from within a call-back handler, except when aborting + (resumable = 0) an already suspended parser. Some call-backs may + still follow because they would otherwise get lost. Examples: + - endElementHandler() for empty elements when stopped in + startElementHandler(), + - endNameSpaceDeclHandler() when stopped in endElementHandler(), + and possibly others. + + Can be called from most handlers, including DTD related call-backs, + except when parsing an external parameter entity and resumable != 0. + Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise. + Possible error codes: + - XML_ERROR_SUSPENDED: when suspending an already suspended parser. + - XML_ERROR_FINISHED: when the parser has already finished. + - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE. + + When resumable != 0 (true) then parsing is suspended, that is, + XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED. + Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer() + return XML_STATUS_ERROR with error code XML_ERROR_ABORTED. + + *Note*: + This will be applied to the current parser instance only, that is, if + there is a parent parser then it will continue parsing when the + externalEntityRefHandler() returns. It is up to the implementation of + the externalEntityRefHandler() to call XML_StopParser() on the parent + parser (recursively), if one wants to stop parsing altogether. + + When suspended, parsing can be resumed by calling XML_ResumeParser(). +*/ +XMLPARSEAPI(enum XML_Status) +XML_StopParser(XML_Parser parser, XML_Bool resumable); + +/* Resumes parsing after it has been suspended with XML_StopParser(). + Must not be called from within a handler call-back. Returns same + status codes as XML_Parse() or XML_ParseBuffer(). + Additional error code XML_ERROR_NOT_SUSPENDED possible. + + *Note*: + This must be called on the most deeply nested child parser instance + first, and on its parent parser only after the child parser has finished, + to be applied recursively until the document entity's parser is restarted. + That is, the parent parser will not resume by itself and it is up to the + application to call XML_ResumeParser() on it at the appropriate moment. +*/ +XMLPARSEAPI(enum XML_Status) +XML_ResumeParser(XML_Parser parser); + +enum XML_Parsing { + XML_INITIALIZED, + XML_PARSING, + XML_FINISHED, + XML_SUSPENDED +}; + +typedef struct { + enum XML_Parsing parsing; + XML_Bool finalBuffer; +} XML_ParsingStatus; + +/* Returns status of parser with respect to being initialized, parsing, + finished, or suspended and processing the final buffer. + XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus, + XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED +*/ +XMLPARSEAPI(void) +XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status); + +/* Creates an XML_Parser object that can parse an external general + entity; context is a '\0'-terminated string specifying the parse + context; encoding is a '\0'-terminated string giving the name of + the externally specified encoding, or NULL if there is no + externally specified encoding. The context string consists of a + sequence of tokens separated by formfeeds (\f); a token consisting + of a name specifies that the general entity of the name is open; a + token of the form prefix=uri specifies the namespace for a + particular prefix; a token of the form =uri specifies the default + namespace. This can be called at any point after the first call to + an ExternalEntityRefHandler so longer as the parser has not yet + been freed. The new parser is completely independent and may + safely be used in a separate thread. The handlers and userData are + initialized from the parser argument. Returns NULL if out of memory. + Otherwise returns a new XML_Parser object. +*/ +XMLPARSEAPI(XML_Parser) +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD + subset). If parsing of parameter entities is enabled, then + references to external parameter entities (including the external + DTD subset) will be passed to the handler set with + XML_SetExternalEntityRefHandler. The context passed will be 0. + + Unlike external general entities, external parameter entities can + only be parsed synchronously. If the external parameter entity is + to be parsed, it must be parsed during the call to the external + entity ref handler: the complete sequence of + XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and + XML_ParserFree calls must be made during this call. After + XML_ExternalEntityParserCreate has been called to create the parser + for the external parameter entity (context must be 0 for this + call), it is illegal to make any calls on the old parser until + XML_ParserFree has been called on the newly created parser. + If the library has been compiled without support for parameter + entity parsing (ie without XML_DTD being defined), then + XML_SetParamEntityParsing will return 0 if parsing of parameter + entities is requested; otherwise it will return non-zero. + Note: If XML_SetParamEntityParsing is called after XML_Parse or + XML_ParseBuffer, then it has no effect and will always return 0. +*/ +XMLPARSEAPI(int) +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +/* Sets the hash salt to use for internal hash calculations. + Helps in preventing DoS attacks based on predicting hash + function behavior. This must be called before parsing is started. + Returns 1 if successful, 0 when called after parsing has started. +*/ +XMLPARSEAPI(int) +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt); + +/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then + XML_GetErrorCode returns information about the error. +*/ +XMLPARSEAPI(enum XML_Error) +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse + location. They may be called from any callback called to report + some parse event; in this case the location is the location of the + first of the sequence of characters that generated the event. When + called from callbacks generated by declarations in the document + prologue, the location identified isn't as neatly defined, but will + be within the relevant markup. When called outside of the callback + functions, the position indicated will be just past the last parse + event (regardless of whether there was an associated callback). + + They may also be called after returning from a call to XML_Parse + or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then + the location is the location of the character at which the error + was detected; otherwise the location is the location of the last + parse event, as described above. +*/ +XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser); +XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser); +XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. + Returns 0 if the event is in an internal entity. +*/ +XMLPARSEAPI(int) +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a NULL pointer. Also returns a NULL pointer if a parse isn't + active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. +*/ +XMLPARSEAPI(const char *) +XML_GetInputContext(XML_Parser parser, + int *offset, + int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees the content model passed to the element declaration handler */ +XMLPARSEAPI(void) +XML_FreeContentModel(XML_Parser parser, XML_Content *model); + +/* Exposing the memory handling functions used in Expat */ +XMLPARSEAPI(void *) +XML_MemMalloc(XML_Parser parser, size_t size); + +XMLPARSEAPI(void *) +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size); + +XMLPARSEAPI(void) +XML_MemFree(XML_Parser parser, void *ptr); + +/* Frees memory used by the parser. */ +XMLPARSEAPI(void) +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +XMLPARSEAPI(const XML_LChar *) +XML_ErrorString(enum XML_Error code); + +/* Return a string containing the version number of this expat */ +XMLPARSEAPI(const XML_LChar *) +XML_ExpatVersion(void); + +typedef struct { + int major; + int minor; + int micro; +} XML_Expat_Version; + +/* Return an XML_Expat_Version structure containing numeric version + number information for this version of expat. +*/ +XMLPARSEAPI(XML_Expat_Version) +XML_ExpatVersionInfo(void); + +/* Added in Expat 1.95.5. */ +enum XML_FeatureEnum { + XML_FEATURE_END = 0, + XML_FEATURE_UNICODE, + XML_FEATURE_UNICODE_WCHAR_T, + XML_FEATURE_DTD, + XML_FEATURE_CONTEXT_BYTES, + XML_FEATURE_MIN_SIZE, + XML_FEATURE_SIZEOF_XML_CHAR, + XML_FEATURE_SIZEOF_XML_LCHAR, + XML_FEATURE_NS, + XML_FEATURE_LARGE_SIZE, + XML_FEATURE_ATTR_INFO + /* Additional features must be added to the end of this enum. */ +}; + +typedef struct { + enum XML_FeatureEnum feature; + const XML_LChar *name; + long int value; +} XML_Feature; + +XMLPARSEAPI(const XML_Feature *) +XML_GetFeatureList(void); + + +/* Expat follows the GNU/Linux convention of odd number minor version for + beta/development releases and even number minor version for stable + releases. Micro is bumped with each release, and set to 0 with each + change to major or minor version. +*/ +#define XML_MAJOR_VERSION 2 +#define XML_MINOR_VERSION 1 +#define XML_MICRO_VERSION 0 + +#ifdef __cplusplus +} +#endif + +#endif /* not Expat_INCLUDED */ diff -Nru simgear-2.10.0/3rdparty/expat/utf8tab.h simgear-3.0.0/3rdparty/expat/utf8tab.h --- simgear-2.10.0/3rdparty/expat/utf8tab.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/utf8tab.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,63 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (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.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + + +/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4, +/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM, diff -Nru simgear-2.10.0/3rdparty/expat/xmldef.h simgear-3.0.0/3rdparty/expat/xmldef.h --- simgear-2.10.0/3rdparty/expat/xmldef.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/xmldef.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,63 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (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.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + +#include + +#ifdef XML_WINLIB + +#define WIN32_LEAN_AND_MEAN +#define STRICT +#include + +#define malloc(x) HeapAlloc(GetProcessHeap(), 0, (x)) +#define calloc(x, y) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x)*(y)) +#define free(x) HeapFree(GetProcessHeap(), 0, (x)) +#define realloc(x, y) HeapReAlloc(GetProcessHeap(), 0, x, y) +#define abort() /* as nothing */ + +#else /* not XML_WINLIB */ + +#include + +#endif /* not XML_WINLIB */ + +/* This file can be used for any definitions needed in +particular environments. */ + +#ifdef MOZILLA + +#include +#define malloc(x) PR_Malloc(x) +#define realloc(x, y) PR_Realloc((x), (y)) +#define calloc(x, y) PR_Calloc((x),(y)) +#define free(x) PR_Free(x) +#define int int32 + +#endif /* MOZILLA */ diff -Nru simgear-2.10.0/3rdparty/expat/xmlparse.c simgear-3.0.0/3rdparty/expat/xmlparse.c --- simgear-2.10.0/3rdparty/expat/xmlparse.c 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/xmlparse.c 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,6403 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include +#include /* memset(), memcpy() */ +#include +#include /* UINT_MAX */ +#include /* time() */ + +#define XML_BUILDING_EXPAT 1 + +#ifdef COMPILED_FROM_DSP +#include "winconfig.h" +#elif defined(MACOS_CLASSIC) +#include "macconfig.h" +#elif defined(__amigaos__) +#include "amigaconfig.h" +#elif defined(__WATCOMC__) +#include "watcomconfig.h" +#elif defined(HAVE_EXPAT_CONFIG_H) +#include "expat_config.h" +#endif /* ndef COMPILED_FROM_DSP */ + +#include "ascii.h" +#include "sg_expat.h" + +#ifdef XML_UNICODE +#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX +#define XmlConvert XmlUtf16Convert +#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding +#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS +#define XmlEncode XmlUtf16Encode +/* Using pointer subtraction to convert to integer type. */ +#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1)) +typedef unsigned short ICHAR; +#else +#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX +#define XmlConvert XmlUtf8Convert +#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding +#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS +#define XmlEncode XmlUtf8Encode +#define MUST_CONVERT(enc, s) (!(enc)->isUtf8) +typedef char ICHAR; +#endif + + +#ifndef XML_NS + +#define XmlInitEncodingNS XmlInitEncoding +#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding +#undef XmlGetInternalEncodingNS +#define XmlGetInternalEncodingNS XmlGetInternalEncoding +#define XmlParseXmlDeclNS XmlParseXmlDecl + +#endif + +#ifdef XML_UNICODE + +#ifdef XML_UNICODE_WCHAR_T +#define XML_T(x) (const wchar_t)x +#define XML_L(x) L ## x +#else +#define XML_T(x) (const unsigned short)x +#define XML_L(x) x +#endif + +#else + +#define XML_T(x) x +#define XML_L(x) x + +#endif + +/* Round up n to be a multiple of sz, where sz is a power of 2. */ +#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) + +/* Handle the case where memmove() doesn't exist. */ +#ifndef HAVE_MEMMOVE +#ifdef HAVE_BCOPY +#define memmove(d,s,l) bcopy((s),(d),(l)) +#else +#error memmove does not exist on this platform, nor is a substitute available +#endif /* HAVE_BCOPY */ +#endif /* HAVE_MEMMOVE */ + +#include "internal.h" +#include "xmltok.h" +#include "xmlrole.h" + +typedef const XML_Char *KEY; + +typedef struct { + KEY name; +} NAMED; + +typedef struct { + NAMED **v; + unsigned char power; + size_t size; + size_t used; + const XML_Memory_Handling_Suite *mem; +} HASH_TABLE; + +/* Basic character hash algorithm, taken from Python's string hash: + h = h * 1000003 ^ character, the constant being a prime number. + +*/ +#ifdef XML_UNICODE +#define CHAR_HASH(h, c) \ + (((h) * 0xF4243) ^ (unsigned short)(c)) +#else +#define CHAR_HASH(h, c) \ + (((h) * 0xF4243) ^ (unsigned char)(c)) +#endif + +/* For probing (after a collision) we need a step size relative prime + to the hash table size, which is a power of 2. We use double-hashing, + since we can calculate a second hash value cheaply by taking those bits + of the first hash value that were discarded (masked out) when the table + index was calculated: index = hash & mask, where mask = table->size - 1. + We limit the maximum step size to table->size / 4 (mask >> 2) and make + it odd, since odd numbers are always relative prime to a power of 2. +*/ +#define SECOND_HASH(hash, mask, power) \ + ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2)) +#define PROBE_STEP(hash, mask, power) \ + ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1)) + +typedef struct { + NAMED **p; + NAMED **end; +} HASH_TABLE_ITER; + +#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */ +#define INIT_DATA_BUF_SIZE 1024 +#define INIT_ATTS_SIZE 16 +#define INIT_ATTS_VERSION 0xFFFFFFFF +#define INIT_BLOCK_SIZE 1024 +#define INIT_BUFFER_SIZE 1024 + +#define EXPAND_SPARE 24 + +typedef struct binding { + struct prefix *prefix; + struct binding *nextTagBinding; + struct binding *prevPrefixBinding; + const struct attribute_id *attId; + XML_Char *uri; + int uriLen; + int uriAlloc; +} BINDING; + +typedef struct prefix { + const XML_Char *name; + BINDING *binding; +} PREFIX; + +typedef struct { + const XML_Char *str; + const XML_Char *localPart; + const XML_Char *prefix; + int strLen; + int uriLen; + int prefixLen; +} TAG_NAME; + +/* TAG represents an open element. + The name of the element is stored in both the document and API + encodings. The memory buffer 'buf' is a separately-allocated + memory area which stores the name. During the XML_Parse()/ + XMLParseBuffer() when the element is open, the memory for the 'raw' + version of the name (in the document encoding) is shared with the + document buffer. If the element is open across calls to + XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to + contain the 'raw' name as well. + + A parser re-uses these structures, maintaining a list of allocated + TAG objects in a free list. +*/ +typedef struct tag { + struct tag *parent; /* parent of this element */ + const char *rawName; /* tagName in the original encoding */ + int rawNameLength; + TAG_NAME name; /* tagName in the API encoding */ + char *buf; /* buffer for name components */ + char *bufEnd; /* end of the buffer */ + BINDING *bindings; +} TAG; + +typedef struct { + const XML_Char *name; + const XML_Char *textPtr; + int textLen; /* length in XML_Chars */ + int processed; /* # of processed bytes - when suspended */ + const XML_Char *systemId; + const XML_Char *base; + const XML_Char *publicId; + const XML_Char *notation; + XML_Bool open; + XML_Bool is_param; + XML_Bool is_internal; /* true if declared in internal subset outside PE */ +} ENTITY; + +typedef struct { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + const XML_Char * name; + int firstchild; + int lastchild; + int childcnt; + int nextsib; +} CONTENT_SCAFFOLD; + +#define INIT_SCAFFOLD_ELEMENTS 32 + +typedef struct block { + struct block *next; + int size; + XML_Char s[1]; +} BLOCK; + +typedef struct { + BLOCK *blocks; + BLOCK *freeBlocks; + const XML_Char *end; + XML_Char *ptr; + XML_Char *start; + const XML_Memory_Handling_Suite *mem; +} STRING_POOL; + +/* The XML_Char before the name is used to determine whether + an attribute has been specified. */ +typedef struct attribute_id { + XML_Char *name; + PREFIX *prefix; + XML_Bool maybeTokenized; + XML_Bool xmlns; +} ATTRIBUTE_ID; + +typedef struct { + const ATTRIBUTE_ID *id; + XML_Bool isCdata; + const XML_Char *value; +} DEFAULT_ATTRIBUTE; + +typedef struct { + unsigned long version; + unsigned long hash; + const XML_Char *uriName; +} NS_ATT; + +typedef struct { + const XML_Char *name; + PREFIX *prefix; + const ATTRIBUTE_ID *idAtt; + int nDefaultAtts; + int allocDefaultAtts; + DEFAULT_ATTRIBUTE *defaultAtts; +} ELEMENT_TYPE; + +typedef struct { + HASH_TABLE generalEntities; + HASH_TABLE elementTypes; + HASH_TABLE attributeIds; + HASH_TABLE prefixes; + STRING_POOL pool; + STRING_POOL entityValuePool; + /* false once a parameter entity reference has been skipped */ + XML_Bool keepProcessing; + /* true once an internal or external PE reference has been encountered; + this includes the reference to an external subset */ + XML_Bool hasParamEntityRefs; + XML_Bool standalone; +#ifdef XML_DTD + /* indicates if external PE has been read */ + XML_Bool paramEntityRead; + HASH_TABLE paramEntities; +#endif /* XML_DTD */ + PREFIX defaultPrefix; + /* === scaffolding for building content model === */ + XML_Bool in_eldecl; + CONTENT_SCAFFOLD *scaffold; + unsigned contentStringLen; + unsigned scaffSize; + unsigned scaffCount; + int scaffLevel; + int *scaffIndex; +} DTD; + +typedef struct open_internal_entity { + const char *internalEventPtr; + const char *internalEventEndPtr; + struct open_internal_entity *next; + ENTITY *entity; + int startTagLevel; + XML_Bool betweenDecl; /* WFC: PE Between Declarations */ +} OPEN_INTERNAL_ENTITY; + +typedef enum XML_Error PTRCALL Processor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr); + +static Processor prologProcessor; +static Processor prologInitProcessor; +static Processor contentProcessor; +static Processor cdataSectionProcessor; +#ifdef XML_DTD +static Processor ignoreSectionProcessor; +static Processor externalParEntProcessor; +static Processor externalParEntInitProcessor; +static Processor entityValueProcessor; +static Processor entityValueInitProcessor; +#endif /* XML_DTD */ +static Processor epilogProcessor; +static Processor errorProcessor; +static Processor externalEntityInitProcessor; +static Processor externalEntityInitProcessor2; +static Processor externalEntityInitProcessor3; +static Processor externalEntityContentProcessor; +static Processor internalEntityProcessor; + +static enum XML_Error +handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName); +static enum XML_Error +processXmlDecl(XML_Parser parser, int isGeneralTextEntity, + const char *s, const char *next); +static enum XML_Error +initializeEncoding(XML_Parser parser); +static enum XML_Error +doProlog(XML_Parser parser, const ENCODING *enc, const char *s, + const char *end, int tok, const char *next, const char **nextPtr, + XML_Bool haveMore); +static enum XML_Error +processInternalEntity(XML_Parser parser, ENTITY *entity, + XML_Bool betweenDecl); +static enum XML_Error +doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + const char *start, const char *end, const char **endPtr, + XML_Bool haveMore); +static enum XML_Error +doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, + const char *end, const char **nextPtr, XML_Bool haveMore); +#ifdef XML_DTD +static enum XML_Error +doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr, + const char *end, const char **nextPtr, XML_Bool haveMore); +#endif /* XML_DTD */ + +static enum XML_Error +storeAtts(XML_Parser parser, const ENCODING *, const char *s, + TAG_NAME *tagNamePtr, BINDING **bindingsPtr); +static enum XML_Error +addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, + const XML_Char *uri, BINDING **bindingsPtr); +static int +defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata, + XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser); +static enum XML_Error +storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata, + const char *, const char *, STRING_POOL *); +static enum XML_Error +appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata, + const char *, const char *, STRING_POOL *); +static ATTRIBUTE_ID * +getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); +static int +setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *); +static enum XML_Error +storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); +static int +reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end); +static int +reportComment(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); +static void +reportDefault(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); + +static const XML_Char * getContext(XML_Parser parser); +static XML_Bool +setContext(XML_Parser parser, const XML_Char *context); + +static void FASTCALL normalizePublicId(XML_Char *s); + +static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms); +/* do not call if parentParser != NULL */ +static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms); +static void +dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); +static int +dtdCopy(XML_Parser oldParser, + DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); +static int +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); +static NAMED * +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); +static void FASTCALL +hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); +static void FASTCALL hashTableClear(HASH_TABLE *); +static void FASTCALL hashTableDestroy(HASH_TABLE *); +static void FASTCALL +hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); +static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *); + +static void FASTCALL +poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms); +static void FASTCALL poolClear(STRING_POOL *); +static void FASTCALL poolDestroy(STRING_POOL *); +static XML_Char * +poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static XML_Char * +poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static XML_Bool FASTCALL poolGrow(STRING_POOL *pool); +static const XML_Char * FASTCALL +poolCopyString(STRING_POOL *pool, const XML_Char *s); +static const XML_Char * +poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n); +static const XML_Char * FASTCALL +poolAppendString(STRING_POOL *pool, const XML_Char *s); + +static int FASTCALL nextScaffoldPart(XML_Parser parser); +static XML_Content * build_model(XML_Parser parser); +static ELEMENT_TYPE * +getElementType(XML_Parser parser, const ENCODING *enc, + const char *ptr, const char *end); + +static unsigned long generate_hash_secret_salt(void); +static XML_Bool startParsing(XML_Parser parser); + +static XML_Parser +parserCreate(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep, + DTD *dtd); + +static void +parserInit(XML_Parser parser, const XML_Char *encodingName); + +#define poolStart(pool) ((pool)->start) +#define poolEnd(pool) ((pool)->ptr) +#define poolLength(pool) ((pool)->ptr - (pool)->start) +#define poolChop(pool) ((void)--(pool->ptr)) +#define poolLastChar(pool) (((pool)->ptr)[-1]) +#define poolDiscard(pool) ((pool)->ptr = (pool)->start) +#define poolFinish(pool) ((pool)->start = (pool)->ptr) +#define poolAppendChar(pool, c) \ + (((pool)->ptr == (pool)->end && !poolGrow(pool)) \ + ? 0 \ + : ((*((pool)->ptr)++ = c), 1)) + +struct XML_ParserStruct { + /* The first member must be userData so that the XML_GetUserData + macro works. */ + void *m_userData; + void *m_handlerArg; + char *m_buffer; + const XML_Memory_Handling_Suite m_mem; + /* first character to be parsed */ + const char *m_bufferPtr; + /* past last character to be parsed */ + char *m_bufferEnd; + /* allocated end of buffer */ + const char *m_bufferLim; + XML_Index m_parseEndByteIndex; + const char *m_parseEndPtr; + XML_Char *m_dataBuf; + XML_Char *m_dataBufEnd; + XML_StartElementHandler m_startElementHandler; + XML_EndElementHandler m_endElementHandler; + XML_CharacterDataHandler m_characterDataHandler; + XML_ProcessingInstructionHandler m_processingInstructionHandler; + XML_CommentHandler m_commentHandler; + XML_StartCdataSectionHandler m_startCdataSectionHandler; + XML_EndCdataSectionHandler m_endCdataSectionHandler; + XML_DefaultHandler m_defaultHandler; + XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler; + XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler; + XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler; + XML_NotationDeclHandler m_notationDeclHandler; + XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler; + XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler; + XML_NotStandaloneHandler m_notStandaloneHandler; + XML_ExternalEntityRefHandler m_externalEntityRefHandler; + XML_Parser m_externalEntityRefHandlerArg; + XML_SkippedEntityHandler m_skippedEntityHandler; + XML_UnknownEncodingHandler m_unknownEncodingHandler; + XML_ElementDeclHandler m_elementDeclHandler; + XML_AttlistDeclHandler m_attlistDeclHandler; + XML_EntityDeclHandler m_entityDeclHandler; + XML_XmlDeclHandler m_xmlDeclHandler; + const ENCODING *m_encoding; + INIT_ENCODING m_initEncoding; + const ENCODING *m_internalEncoding; + const XML_Char *m_protocolEncodingName; + XML_Bool m_ns; + XML_Bool m_ns_triplets; + void *m_unknownEncodingMem; + void *m_unknownEncodingData; + void *m_unknownEncodingHandlerData; + void (XMLCALL *m_unknownEncodingRelease)(void *); + PROLOG_STATE m_prologState; + Processor *m_processor; + enum XML_Error m_errorCode; + const char *m_eventPtr; + const char *m_eventEndPtr; + const char *m_positionPtr; + OPEN_INTERNAL_ENTITY *m_openInternalEntities; + OPEN_INTERNAL_ENTITY *m_freeInternalEntities; + XML_Bool m_defaultExpandInternalEntities; + int m_tagLevel; + ENTITY *m_declEntity; + const XML_Char *m_doctypeName; + const XML_Char *m_doctypeSysid; + const XML_Char *m_doctypePubid; + const XML_Char *m_declAttributeType; + const XML_Char *m_declNotationName; + const XML_Char *m_declNotationPublicId; + ELEMENT_TYPE *m_declElementType; + ATTRIBUTE_ID *m_declAttributeId; + XML_Bool m_declAttributeIsCdata; + XML_Bool m_declAttributeIsId; + DTD *m_dtd; + const XML_Char *m_curBase; + TAG *m_tagStack; + TAG *m_freeTagList; + BINDING *m_inheritedBindings; + BINDING *m_freeBindingList; + int m_attsSize; + int m_nSpecifiedAtts; + int m_idAttIndex; + ATTRIBUTE *m_atts; + NS_ATT *m_nsAtts; + unsigned long m_nsAttsVersion; + unsigned char m_nsAttsPower; +#ifdef XML_ATTR_INFO + XML_AttrInfo *m_attInfo; +#endif + POSITION m_position; + STRING_POOL m_tempPool; + STRING_POOL m_temp2Pool; + char *m_groupConnector; + unsigned int m_groupSize; + XML_Char m_namespaceSeparator; + XML_Parser m_parentParser; + XML_ParsingStatus m_parsingStatus; +#ifdef XML_DTD + XML_Bool m_isParamEntity; + XML_Bool m_useForeignDTD; + enum XML_ParamEntityParsing m_paramEntityParsing; +#endif + unsigned long m_hash_secret_salt; +}; + +#define MALLOC(s) (parser->m_mem.malloc_fcn((s))) +#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s))) +#define FREE(p) (parser->m_mem.free_fcn((p))) + +#define userData (parser->m_userData) +#define handlerArg (parser->m_handlerArg) +#define startElementHandler (parser->m_startElementHandler) +#define endElementHandler (parser->m_endElementHandler) +#define characterDataHandler (parser->m_characterDataHandler) +#define processingInstructionHandler \ + (parser->m_processingInstructionHandler) +#define commentHandler (parser->m_commentHandler) +#define startCdataSectionHandler \ + (parser->m_startCdataSectionHandler) +#define endCdataSectionHandler (parser->m_endCdataSectionHandler) +#define defaultHandler (parser->m_defaultHandler) +#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler) +#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler) +#define unparsedEntityDeclHandler \ + (parser->m_unparsedEntityDeclHandler) +#define notationDeclHandler (parser->m_notationDeclHandler) +#define startNamespaceDeclHandler \ + (parser->m_startNamespaceDeclHandler) +#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler) +#define notStandaloneHandler (parser->m_notStandaloneHandler) +#define externalEntityRefHandler \ + (parser->m_externalEntityRefHandler) +#define externalEntityRefHandlerArg \ + (parser->m_externalEntityRefHandlerArg) +#define internalEntityRefHandler \ + (parser->m_internalEntityRefHandler) +#define skippedEntityHandler (parser->m_skippedEntityHandler) +#define unknownEncodingHandler (parser->m_unknownEncodingHandler) +#define elementDeclHandler (parser->m_elementDeclHandler) +#define attlistDeclHandler (parser->m_attlistDeclHandler) +#define entityDeclHandler (parser->m_entityDeclHandler) +#define xmlDeclHandler (parser->m_xmlDeclHandler) +#define encoding (parser->m_encoding) +#define initEncoding (parser->m_initEncoding) +#define internalEncoding (parser->m_internalEncoding) +#define unknownEncodingMem (parser->m_unknownEncodingMem) +#define unknownEncodingData (parser->m_unknownEncodingData) +#define unknownEncodingHandlerData \ + (parser->m_unknownEncodingHandlerData) +#define unknownEncodingRelease (parser->m_unknownEncodingRelease) +#define protocolEncodingName (parser->m_protocolEncodingName) +#define ns (parser->m_ns) +#define ns_triplets (parser->m_ns_triplets) +#define prologState (parser->m_prologState) +#define processor (parser->m_processor) +#define errorCode (parser->m_errorCode) +#define eventPtr (parser->m_eventPtr) +#define eventEndPtr (parser->m_eventEndPtr) +#define positionPtr (parser->m_positionPtr) +#define position (parser->m_position) +#define openInternalEntities (parser->m_openInternalEntities) +#define freeInternalEntities (parser->m_freeInternalEntities) +#define defaultExpandInternalEntities \ + (parser->m_defaultExpandInternalEntities) +#define tagLevel (parser->m_tagLevel) +#define buffer (parser->m_buffer) +#define bufferPtr (parser->m_bufferPtr) +#define bufferEnd (parser->m_bufferEnd) +#define parseEndByteIndex (parser->m_parseEndByteIndex) +#define parseEndPtr (parser->m_parseEndPtr) +#define bufferLim (parser->m_bufferLim) +#define dataBuf (parser->m_dataBuf) +#define dataBufEnd (parser->m_dataBufEnd) +#define _dtd (parser->m_dtd) +#define curBase (parser->m_curBase) +#define declEntity (parser->m_declEntity) +#define doctypeName (parser->m_doctypeName) +#define doctypeSysid (parser->m_doctypeSysid) +#define doctypePubid (parser->m_doctypePubid) +#define declAttributeType (parser->m_declAttributeType) +#define declNotationName (parser->m_declNotationName) +#define declNotationPublicId (parser->m_declNotationPublicId) +#define declElementType (parser->m_declElementType) +#define declAttributeId (parser->m_declAttributeId) +#define declAttributeIsCdata (parser->m_declAttributeIsCdata) +#define declAttributeIsId (parser->m_declAttributeIsId) +#define freeTagList (parser->m_freeTagList) +#define freeBindingList (parser->m_freeBindingList) +#define inheritedBindings (parser->m_inheritedBindings) +#define tagStack (parser->m_tagStack) +#define atts (parser->m_atts) +#define attsSize (parser->m_attsSize) +#define nSpecifiedAtts (parser->m_nSpecifiedAtts) +#define idAttIndex (parser->m_idAttIndex) +#define nsAtts (parser->m_nsAtts) +#define nsAttsVersion (parser->m_nsAttsVersion) +#define nsAttsPower (parser->m_nsAttsPower) +#define attInfo (parser->m_attInfo) +#define tempPool (parser->m_tempPool) +#define temp2Pool (parser->m_temp2Pool) +#define groupConnector (parser->m_groupConnector) +#define groupSize (parser->m_groupSize) +#define namespaceSeparator (parser->m_namespaceSeparator) +#define parentParser (parser->m_parentParser) +#define ps_parsing (parser->m_parsingStatus.parsing) +#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer) +#ifdef XML_DTD +#define isParamEntity (parser->m_isParamEntity) +#define useForeignDTD (parser->m_useForeignDTD) +#define paramEntityParsing (parser->m_paramEntityParsing) +#endif /* XML_DTD */ +#define hash_secret_salt (parser->m_hash_secret_salt) + +XML_Parser XMLCALL +XML_ParserCreate(const XML_Char *encodingName) +{ + return XML_ParserCreate_MM(encodingName, NULL, NULL); +} + +XML_Parser XMLCALL +XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) +{ + XML_Char tmp[2]; + *tmp = nsSep; + return XML_ParserCreate_MM(encodingName, NULL, tmp); +} + +static const XML_Char implicitContext[] = { + ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, ASCII_t, ASCII_t, ASCII_p, + ASCII_COLON, ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, + ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g, + ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9, + ASCII_9, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e, + ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0' +}; + +static unsigned long +generate_hash_secret_salt(void) +{ + unsigned int seed = time(NULL) % UINT_MAX; + srand(seed); + return rand(); +} + +static XML_Bool /* only valid for root parser */ +startParsing(XML_Parser parser) +{ + /* hash functions must be initialized before setContext() is called */ + if (hash_secret_salt == 0) + hash_secret_salt = generate_hash_secret_salt(); + if (ns) { + /* implicit context only set for root parser, since child + parsers (i.e. external entity parsers) will inherit it + */ + return setContext(parser, implicitContext); + } + return XML_TRUE; +} + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) +{ + return parserCreate(encodingName, memsuite, nameSep, NULL); +} + +static XML_Parser +parserCreate(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep, + DTD *dtd) +{ + XML_Parser parser; + + if (memsuite) { + XML_Memory_Handling_Suite *mtemp; + parser = (XML_Parser) + memsuite->malloc_fcn(sizeof(struct XML_ParserStruct)); + if (parser != NULL) { + mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); + mtemp->malloc_fcn = memsuite->malloc_fcn; + mtemp->realloc_fcn = memsuite->realloc_fcn; + mtemp->free_fcn = memsuite->free_fcn; + } + } + else { + XML_Memory_Handling_Suite *mtemp; + parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct)); + if (parser != NULL) { + mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); + mtemp->malloc_fcn = malloc; + mtemp->realloc_fcn = realloc; + mtemp->free_fcn = free; + } + } + + if (!parser) + return parser; + + buffer = NULL; + bufferLim = NULL; + + attsSize = INIT_ATTS_SIZE; + atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE)); + if (atts == NULL) { + FREE(parser); + return NULL; + } +#ifdef XML_ATTR_INFO + attInfo = (XML_AttrInfo*)MALLOC(attsSize * sizeof(XML_AttrInfo)); + if (attInfo == NULL) { + FREE(atts); + FREE(parser); + return NULL; + } +#endif + dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char)); + if (dataBuf == NULL) { + FREE(atts); +#ifdef XML_ATTR_INFO + FREE(attInfo); +#endif + FREE(parser); + return NULL; + } + dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE; + + if (dtd) + _dtd = dtd; + else { + _dtd = dtdCreate(&parser->m_mem); + if (_dtd == NULL) { + FREE(dataBuf); + FREE(atts); +#ifdef XML_ATTR_INFO + FREE(attInfo); +#endif + FREE(parser); + return NULL; + } + } + + freeBindingList = NULL; + freeTagList = NULL; + freeInternalEntities = NULL; + + groupSize = 0; + groupConnector = NULL; + + unknownEncodingHandler = NULL; + unknownEncodingHandlerData = NULL; + + namespaceSeparator = ASCII_EXCL; + ns = XML_FALSE; + ns_triplets = XML_FALSE; + + nsAtts = NULL; + nsAttsVersion = 0; + nsAttsPower = 0; + + poolInit(&tempPool, &(parser->m_mem)); + poolInit(&temp2Pool, &(parser->m_mem)); + parserInit(parser, encodingName); + + if (encodingName && !protocolEncodingName) { + XML_ParserFree(parser); + return NULL; + } + + if (nameSep) { + ns = XML_TRUE; + internalEncoding = XmlGetInternalEncodingNS(); + namespaceSeparator = *nameSep; + } + else { + internalEncoding = XmlGetInternalEncoding(); + } + + return parser; +} + +static void +parserInit(XML_Parser parser, const XML_Char *encodingName) +{ + processor = prologInitProcessor; + XmlPrologStateInit(&prologState); + protocolEncodingName = (encodingName != NULL + ? poolCopyString(&tempPool, encodingName) + : NULL); + curBase = NULL; + XmlInitEncoding(&initEncoding, &encoding, 0); + userData = NULL; + handlerArg = NULL; + startElementHandler = NULL; + endElementHandler = NULL; + characterDataHandler = NULL; + processingInstructionHandler = NULL; + commentHandler = NULL; + startCdataSectionHandler = NULL; + endCdataSectionHandler = NULL; + defaultHandler = NULL; + startDoctypeDeclHandler = NULL; + endDoctypeDeclHandler = NULL; + unparsedEntityDeclHandler = NULL; + notationDeclHandler = NULL; + startNamespaceDeclHandler = NULL; + endNamespaceDeclHandler = NULL; + notStandaloneHandler = NULL; + externalEntityRefHandler = NULL; + externalEntityRefHandlerArg = parser; + skippedEntityHandler = NULL; + elementDeclHandler = NULL; + attlistDeclHandler = NULL; + entityDeclHandler = NULL; + xmlDeclHandler = NULL; + bufferPtr = buffer; + bufferEnd = buffer; + parseEndByteIndex = 0; + parseEndPtr = NULL; + declElementType = NULL; + declAttributeId = NULL; + declEntity = NULL; + doctypeName = NULL; + doctypeSysid = NULL; + doctypePubid = NULL; + declAttributeType = NULL; + declNotationName = NULL; + declNotationPublicId = NULL; + declAttributeIsCdata = XML_FALSE; + declAttributeIsId = XML_FALSE; + memset(&position, 0, sizeof(POSITION)); + errorCode = XML_ERROR_NONE; + eventPtr = NULL; + eventEndPtr = NULL; + positionPtr = NULL; + openInternalEntities = NULL; + defaultExpandInternalEntities = XML_TRUE; + tagLevel = 0; + tagStack = NULL; + inheritedBindings = NULL; + nSpecifiedAtts = 0; + unknownEncodingMem = NULL; + unknownEncodingRelease = NULL; + unknownEncodingData = NULL; + parentParser = NULL; + ps_parsing = XML_INITIALIZED; +#ifdef XML_DTD + isParamEntity = XML_FALSE; + useForeignDTD = XML_FALSE; + paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif + hash_secret_salt = 0; +} + +/* moves list of bindings to freeBindingList */ +static void FASTCALL +moveToFreeBindingList(XML_Parser parser, BINDING *bindings) +{ + while (bindings) { + BINDING *b = bindings; + bindings = bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + } +} + +XML_Bool XMLCALL +XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) +{ + TAG *tStk; + OPEN_INTERNAL_ENTITY *openEntityList; + if (parentParser) + return XML_FALSE; + /* move tagStack to freeTagList */ + tStk = tagStack; + while (tStk) { + TAG *tag = tStk; + tStk = tStk->parent; + tag->parent = freeTagList; + moveToFreeBindingList(parser, tag->bindings); + tag->bindings = NULL; + freeTagList = tag; + } + /* move openInternalEntities to freeInternalEntities */ + openEntityList = openInternalEntities; + while (openEntityList) { + OPEN_INTERNAL_ENTITY *openEntity = openEntityList; + openEntityList = openEntity->next; + openEntity->next = freeInternalEntities; + freeInternalEntities = openEntity; + } + moveToFreeBindingList(parser, inheritedBindings); + FREE(unknownEncodingMem); + if (unknownEncodingRelease) + unknownEncodingRelease(unknownEncodingData); + poolClear(&tempPool); + poolClear(&temp2Pool); + parserInit(parser, encodingName); + dtdReset(_dtd, &parser->m_mem); + return XML_TRUE; +} + +enum XML_Status XMLCALL +XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) +{ + /* Block after XML_Parse()/XML_ParseBuffer() has been called. + XXX There's no way for the caller to determine which of the + XXX possible error cases caused the XML_STATUS_ERROR return. + */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return XML_STATUS_ERROR; + if (encodingName == NULL) + protocolEncodingName = NULL; + else { + protocolEncodingName = poolCopyString(&tempPool, encodingName); + if (!protocolEncodingName) + return XML_STATUS_ERROR; + } + return XML_STATUS_OK; +} + +XML_Parser XMLCALL +XML_ExternalEntityParserCreate(XML_Parser oldParser, + const XML_Char *context, + const XML_Char *encodingName) +{ + XML_Parser parser = oldParser; + DTD *newDtd = NULL; + DTD *oldDtd = _dtd; + XML_StartElementHandler oldStartElementHandler = startElementHandler; + XML_EndElementHandler oldEndElementHandler = endElementHandler; + XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler; + XML_ProcessingInstructionHandler oldProcessingInstructionHandler + = processingInstructionHandler; + XML_CommentHandler oldCommentHandler = commentHandler; + XML_StartCdataSectionHandler oldStartCdataSectionHandler + = startCdataSectionHandler; + XML_EndCdataSectionHandler oldEndCdataSectionHandler + = endCdataSectionHandler; + XML_DefaultHandler oldDefaultHandler = defaultHandler; + XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler + = unparsedEntityDeclHandler; + XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler; + XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler + = startNamespaceDeclHandler; + XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler + = endNamespaceDeclHandler; + XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler; + XML_ExternalEntityRefHandler oldExternalEntityRefHandler + = externalEntityRefHandler; + XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler; + XML_UnknownEncodingHandler oldUnknownEncodingHandler + = unknownEncodingHandler; + XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler; + XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler; + XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler; + XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler; + ELEMENT_TYPE * oldDeclElementType = declElementType; + + void *oldUserData = userData; + void *oldHandlerArg = handlerArg; + XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities; + XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg; +#ifdef XML_DTD + enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing; + int oldInEntityValue = prologState.inEntityValue; +#endif + XML_Bool oldns_triplets = ns_triplets; + /* Note that the new parser shares the same hash secret as the old + parser, so that dtdCopy and copyEntityTable can lookup values + from hash tables associated with either parser without us having + to worry which hash secrets each table has. + */ + unsigned long oldhash_secret_salt = hash_secret_salt; + +#ifdef XML_DTD + if (!context) + newDtd = oldDtd; +#endif /* XML_DTD */ + + /* Note that the magical uses of the pre-processor to make field + access look more like C++ require that `parser' be overwritten + here. This makes this function more painful to follow than it + would be otherwise. + */ + if (ns) { + XML_Char tmp[2]; + *tmp = namespaceSeparator; + parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd); + } + else { + parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd); + } + + if (!parser) + return NULL; + + startElementHandler = oldStartElementHandler; + endElementHandler = oldEndElementHandler; + characterDataHandler = oldCharacterDataHandler; + processingInstructionHandler = oldProcessingInstructionHandler; + commentHandler = oldCommentHandler; + startCdataSectionHandler = oldStartCdataSectionHandler; + endCdataSectionHandler = oldEndCdataSectionHandler; + defaultHandler = oldDefaultHandler; + unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler; + notationDeclHandler = oldNotationDeclHandler; + startNamespaceDeclHandler = oldStartNamespaceDeclHandler; + endNamespaceDeclHandler = oldEndNamespaceDeclHandler; + notStandaloneHandler = oldNotStandaloneHandler; + externalEntityRefHandler = oldExternalEntityRefHandler; + skippedEntityHandler = oldSkippedEntityHandler; + unknownEncodingHandler = oldUnknownEncodingHandler; + elementDeclHandler = oldElementDeclHandler; + attlistDeclHandler = oldAttlistDeclHandler; + entityDeclHandler = oldEntityDeclHandler; + xmlDeclHandler = oldXmlDeclHandler; + declElementType = oldDeclElementType; + userData = oldUserData; + if (oldUserData == oldHandlerArg) + handlerArg = userData; + else + handlerArg = parser; + if (oldExternalEntityRefHandlerArg != oldParser) + externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; + defaultExpandInternalEntities = oldDefaultExpandInternalEntities; + ns_triplets = oldns_triplets; + hash_secret_salt = oldhash_secret_salt; + parentParser = oldParser; +#ifdef XML_DTD + paramEntityParsing = oldParamEntityParsing; + prologState.inEntityValue = oldInEntityValue; + if (context) { +#endif /* XML_DTD */ + if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem) + || !setContext(parser, context)) { + XML_ParserFree(parser); + return NULL; + } + processor = externalEntityInitProcessor; +#ifdef XML_DTD + } + else { + /* The DTD instance referenced by _dtd is shared between the document's + root parser and external PE parsers, therefore one does not need to + call setContext. In addition, one also *must* not call setContext, + because this would overwrite existing prefix->binding pointers in + _dtd with ones that get destroyed with the external PE parser. + This would leave those prefixes with dangling pointers. + */ + isParamEntity = XML_TRUE; + XmlPrologStateInitExternalEntity(&prologState); + processor = externalParEntInitProcessor; + } +#endif /* XML_DTD */ + return parser; +} + +static void FASTCALL +destroyBindings(BINDING *bindings, XML_Parser parser) +{ + for (;;) { + BINDING *b = bindings; + if (!b) + break; + bindings = b->nextTagBinding; + FREE(b->uri); + FREE(b); + } +} + +void XMLCALL +XML_ParserFree(XML_Parser parser) +{ + TAG *tagList; + OPEN_INTERNAL_ENTITY *entityList; + if (parser == NULL) + return; + /* free tagStack and freeTagList */ + tagList = tagStack; + for (;;) { + TAG *p; + if (tagList == NULL) { + if (freeTagList == NULL) + break; + tagList = freeTagList; + freeTagList = NULL; + } + p = tagList; + tagList = tagList->parent; + FREE(p->buf); + destroyBindings(p->bindings, parser); + FREE(p); + } + /* free openInternalEntities and freeInternalEntities */ + entityList = openInternalEntities; + for (;;) { + OPEN_INTERNAL_ENTITY *openEntity; + if (entityList == NULL) { + if (freeInternalEntities == NULL) + break; + entityList = freeInternalEntities; + freeInternalEntities = NULL; + } + openEntity = entityList; + entityList = entityList->next; + FREE(openEntity); + } + + destroyBindings(freeBindingList, parser); + destroyBindings(inheritedBindings, parser); + poolDestroy(&tempPool); + poolDestroy(&temp2Pool); +#ifdef XML_DTD + /* external parameter entity parsers share the DTD structure + parser->m_dtd with the root parser, so we must not destroy it + */ + if (!isParamEntity && _dtd) +#else + if (_dtd) +#endif /* XML_DTD */ + dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem); + FREE((void *)atts); +#ifdef XML_ATTR_INFO + FREE((void *)attInfo); +#endif + FREE(groupConnector); + FREE(buffer); + FREE(dataBuf); + FREE(nsAtts); + FREE(unknownEncodingMem); + if (unknownEncodingRelease) + unknownEncodingRelease(unknownEncodingData); + FREE(parser); +} + +void XMLCALL +XML_UseParserAsHandlerArg(XML_Parser parser) +{ + handlerArg = parser; +} + +enum XML_Error XMLCALL +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD) +{ +#ifdef XML_DTD + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING; + useForeignDTD = useDTD; + return XML_ERROR_NONE; +#else + return XML_ERROR_FEATURE_REQUIRES_XML_DTD; +#endif +} + +void XMLCALL +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return; + ns_triplets = do_nst ? XML_TRUE : XML_FALSE; +} + +void XMLCALL +XML_SetUserData(XML_Parser parser, void *p) +{ + if (handlerArg == userData) + handlerArg = userData = p; + else + userData = p; +} + +enum XML_Status XMLCALL +XML_SetBase(XML_Parser parser, const XML_Char *p) +{ + if (p) { + p = poolCopyString(&_dtd->pool, p); + if (!p) + return XML_STATUS_ERROR; + curBase = p; + } + else + curBase = NULL; + return XML_STATUS_OK; +} + +const XML_Char * XMLCALL +XML_GetBase(XML_Parser parser) +{ + return curBase; +} + +int XMLCALL +XML_GetSpecifiedAttributeCount(XML_Parser parser) +{ + return nSpecifiedAtts; +} + +int XMLCALL +XML_GetIdAttributeIndex(XML_Parser parser) +{ + return idAttIndex; +} + +#ifdef XML_ATTR_INFO +const XML_AttrInfo * XMLCALL +XML_GetAttributeInfo(XML_Parser parser) +{ + return attInfo; +} +#endif + +void XMLCALL +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end) +{ + startElementHandler = start; + endElementHandler = end; +} + +void XMLCALL +XML_SetStartElementHandler(XML_Parser parser, + XML_StartElementHandler start) { + startElementHandler = start; +} + +void XMLCALL +XML_SetEndElementHandler(XML_Parser parser, + XML_EndElementHandler end) { + endElementHandler = end; +} + +void XMLCALL +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler) +{ + characterDataHandler = handler; +} + +void XMLCALL +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler) +{ + processingInstructionHandler = handler; +} + +void XMLCALL +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler) +{ + commentHandler = handler; +} + +void XMLCALL +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end) +{ + startCdataSectionHandler = start; + endCdataSectionHandler = end; +} + +void XMLCALL +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start) { + startCdataSectionHandler = start; +} + +void XMLCALL +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end) { + endCdataSectionHandler = end; +} + +void XMLCALL +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler) +{ + defaultHandler = handler; + defaultExpandInternalEntities = XML_FALSE; +} + +void XMLCALL +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler) +{ + defaultHandler = handler; + defaultExpandInternalEntities = XML_TRUE; +} + +void XMLCALL +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end) +{ + startDoctypeDeclHandler = start; + endDoctypeDeclHandler = end; +} + +void XMLCALL +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start) { + startDoctypeDeclHandler = start; +} + +void XMLCALL +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end) { + endDoctypeDeclHandler = end; +} + +void XMLCALL +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler) +{ + unparsedEntityDeclHandler = handler; +} + +void XMLCALL +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler) +{ + notationDeclHandler = handler; +} + +void XMLCALL +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end) +{ + startNamespaceDeclHandler = start; + endNamespaceDeclHandler = end; +} + +void XMLCALL +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start) { + startNamespaceDeclHandler = start; +} + +void XMLCALL +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end) { + endNamespaceDeclHandler = end; +} + +void XMLCALL +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler) +{ + notStandaloneHandler = handler; +} + +void XMLCALL +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler) +{ + externalEntityRefHandler = handler; +} + +void XMLCALL +XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg) +{ + if (arg) + externalEntityRefHandlerArg = (XML_Parser)arg; + else + externalEntityRefHandlerArg = parser; +} + +void XMLCALL +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler) +{ + skippedEntityHandler = handler; +} + +void XMLCALL +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *data) +{ + unknownEncodingHandler = handler; + unknownEncodingHandlerData = data; +} + +void XMLCALL +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl) +{ + elementDeclHandler = eldecl; +} + +void XMLCALL +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl) +{ + attlistDeclHandler = attdecl; +} + +void XMLCALL +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler) +{ + entityDeclHandler = handler; +} + +void XMLCALL +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler handler) { + xmlDeclHandler = handler; +} + +int XMLCALL +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing peParsing) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; +#ifdef XML_DTD + paramEntityParsing = peParsing; + return 1; +#else + return peParsing == XML_PARAM_ENTITY_PARSING_NEVER; +#endif +} + +int XMLCALL +XML_SetHashSalt(XML_Parser parser, + unsigned long hash_salt) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; + hash_secret_salt = hash_salt; + return 1; +} + +enum XML_Status XMLCALL +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) +{ + switch (ps_parsing) { + case XML_SUSPENDED: + errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } + default: + ps_parsing = XML_PARSING; + } + + if (len == 0) { + ps_finalBuffer = (XML_Bool)isFinal; + if (!isFinal) + return XML_STATUS_OK; + positionPtr = bufferPtr; + parseEndPtr = bufferEnd; + + /* If data are left over from last buffer, and we now know that these + data are the final chunk of input, then we have to check them again + to detect errors based on that fact. + */ + errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr); + + if (errorCode == XML_ERROR_NONE) { + switch (ps_parsing) { + case XML_SUSPENDED: + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + positionPtr = bufferPtr; + return XML_STATUS_SUSPENDED; + case XML_INITIALIZED: + case XML_PARSING: + ps_parsing = XML_FINISHED; + /* fall through */ + default: + return XML_STATUS_OK; + } + } + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } +#ifndef XML_CONTEXT_BYTES + else if (bufferPtr == bufferEnd) { + const char *end; + int nLeftOver; + enum XML_Error result; + parseEndByteIndex += len; + positionPtr = s; + ps_finalBuffer = (XML_Bool)isFinal; + + errorCode = processor(parser, s, parseEndPtr = s + len, &end); + + if (errorCode != XML_ERROR_NONE) { + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + else { + switch (ps_parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + if (isFinal) { + ps_parsing = XML_FINISHED; + return XML_STATUS_OK; + } + /* fall through */ + default: + result = XML_STATUS_OK; + } + } + + XmlUpdatePosition(encoding, positionPtr, end, &position); + nLeftOver = s + len - end; + if (nLeftOver) { + if (buffer == NULL || nLeftOver > bufferLim - buffer) { + /* FIXME avoid integer overflow */ + char *temp; + temp = (buffer == NULL + ? (char *)MALLOC(len * 2) + : (char *)REALLOC(buffer, len * 2)); + if (temp == NULL) { + errorCode = XML_ERROR_NO_MEMORY; + eventPtr = eventEndPtr = NULL; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + buffer = temp; + bufferLim = buffer + len * 2; + } + memcpy(buffer, end, nLeftOver); + } + bufferPtr = buffer; + bufferEnd = buffer + nLeftOver; + positionPtr = bufferPtr; + parseEndPtr = bufferEnd; + eventPtr = bufferPtr; + eventEndPtr = bufferPtr; + return result; + } +#endif /* not defined XML_CONTEXT_BYTES */ + else { + void *buff = XML_GetBuffer(parser, len); + if (buff == NULL) + return XML_STATUS_ERROR; + else { + memcpy(buff, s, len); + return XML_ParseBuffer(parser, len, isFinal); + } + } +} + +enum XML_Status XMLCALL +XML_ParseBuffer(XML_Parser parser, int len, int isFinal) +{ + const char *start; + enum XML_Status result = XML_STATUS_OK; + + switch (ps_parsing) { + case XML_SUSPENDED: + errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + case XML_INITIALIZED: + if (parentParser == NULL && !startParsing(parser)) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } + default: + ps_parsing = XML_PARSING; + } + + start = bufferPtr; + positionPtr = start; + bufferEnd += len; + parseEndPtr = bufferEnd; + parseEndByteIndex += len; + ps_finalBuffer = (XML_Bool)isFinal; + + errorCode = processor(parser, start, parseEndPtr, &bufferPtr); + + if (errorCode != XML_ERROR_NONE) { + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + else { + switch (ps_parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + if (isFinal) { + ps_parsing = XML_FINISHED; + return result; + } + default: ; /* should not happen */ + } + } + + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + positionPtr = bufferPtr; + return result; +} + +void * XMLCALL +XML_GetBuffer(XML_Parser parser, int len) +{ + switch (ps_parsing) { + case XML_SUSPENDED: + errorCode = XML_ERROR_SUSPENDED; + return NULL; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return NULL; + default: ; + } + + if (len > bufferLim - bufferEnd) { + /* FIXME avoid integer overflow */ + int neededSize = len + (int)(bufferEnd - bufferPtr); +#ifdef XML_CONTEXT_BYTES + int keep = (int)(bufferPtr - buffer); + + if (keep > XML_CONTEXT_BYTES) + keep = XML_CONTEXT_BYTES; + neededSize += keep; +#endif /* defined XML_CONTEXT_BYTES */ + if (neededSize <= bufferLim - buffer) { +#ifdef XML_CONTEXT_BYTES + if (keep < bufferPtr - buffer) { + int offset = (int)(bufferPtr - buffer) - keep; + memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep); + bufferEnd -= offset; + bufferPtr -= offset; + } +#else + memmove(buffer, bufferPtr, bufferEnd - bufferPtr); + bufferEnd = buffer + (bufferEnd - bufferPtr); + bufferPtr = buffer; +#endif /* not defined XML_CONTEXT_BYTES */ + } + else { + char *newBuf; + int bufferSize = (int)(bufferLim - bufferPtr); + if (bufferSize == 0) + bufferSize = INIT_BUFFER_SIZE; + do { + bufferSize *= 2; + } while (bufferSize < neededSize); + newBuf = (char *)MALLOC(bufferSize); + if (newBuf == 0) { + errorCode = XML_ERROR_NO_MEMORY; + return NULL; + } + bufferLim = newBuf + bufferSize; +#ifdef XML_CONTEXT_BYTES + if (bufferPtr) { + int keep = (int)(bufferPtr - buffer); + if (keep > XML_CONTEXT_BYTES) + keep = XML_CONTEXT_BYTES; + memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep); + FREE(buffer); + buffer = newBuf; + bufferEnd = buffer + (bufferEnd - bufferPtr) + keep; + bufferPtr = buffer + keep; + } + else { + bufferEnd = newBuf + (bufferEnd - bufferPtr); + bufferPtr = buffer = newBuf; + } +#else + if (bufferPtr) { + memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr); + FREE(buffer); + } + bufferEnd = newBuf + (bufferEnd - bufferPtr); + bufferPtr = buffer = newBuf; +#endif /* not defined XML_CONTEXT_BYTES */ + } + eventPtr = eventEndPtr = NULL; + positionPtr = NULL; + } + return bufferEnd; +} + +enum XML_Status XMLCALL +XML_StopParser(XML_Parser parser, XML_Bool resumable) +{ + switch (ps_parsing) { + case XML_SUSPENDED: + if (resumable) { + errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + } + ps_parsing = XML_FINISHED; + break; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + default: + if (resumable) { +#ifdef XML_DTD + if (isParamEntity) { + errorCode = XML_ERROR_SUSPEND_PE; + return XML_STATUS_ERROR; + } +#endif + ps_parsing = XML_SUSPENDED; + } + else + ps_parsing = XML_FINISHED; + } + return XML_STATUS_OK; +} + +enum XML_Status XMLCALL +XML_ResumeParser(XML_Parser parser) +{ + enum XML_Status result = XML_STATUS_OK; + + if (ps_parsing != XML_SUSPENDED) { + errorCode = XML_ERROR_NOT_SUSPENDED; + return XML_STATUS_ERROR; + } + ps_parsing = XML_PARSING; + + errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr); + + if (errorCode != XML_ERROR_NONE) { + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + else { + switch (ps_parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + if (ps_finalBuffer) { + ps_parsing = XML_FINISHED; + return result; + } + default: ; + } + } + + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + positionPtr = bufferPtr; + return result; +} + +void XMLCALL +XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status) +{ + assert(status != NULL); + *status = parser->m_parsingStatus; +} + +enum XML_Error XMLCALL +XML_GetErrorCode(XML_Parser parser) +{ + return errorCode; +} + +XML_Index XMLCALL +XML_GetCurrentByteIndex(XML_Parser parser) +{ + if (eventPtr) + return parseEndByteIndex - (parseEndPtr - eventPtr); + return -1; +} + +int XMLCALL +XML_GetCurrentByteCount(XML_Parser parser) +{ + if (eventEndPtr && eventPtr) + return (int)(eventEndPtr - eventPtr); + return 0; +} + +const char * XMLCALL +XML_GetInputContext(XML_Parser parser, int *offset, int *size) +{ +#ifdef XML_CONTEXT_BYTES + if (eventPtr && buffer) { + *offset = (int)(eventPtr - buffer); + *size = (int)(bufferEnd - buffer); + return buffer; + } +#endif /* defined XML_CONTEXT_BYTES */ + return (char *) 0; +} + +XML_Size XMLCALL +XML_GetCurrentLineNumber(XML_Parser parser) +{ + if (eventPtr && eventPtr >= positionPtr) { + XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); + positionPtr = eventPtr; + } + return position.lineNumber + 1; +} + +XML_Size XMLCALL +XML_GetCurrentColumnNumber(XML_Parser parser) +{ + if (eventPtr && eventPtr >= positionPtr) { + XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); + positionPtr = eventPtr; + } + return position.columnNumber; +} + +void XMLCALL +XML_FreeContentModel(XML_Parser parser, XML_Content *model) +{ + FREE(model); +} + +void * XMLCALL +XML_MemMalloc(XML_Parser parser, size_t size) +{ + return MALLOC(size); +} + +void * XMLCALL +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) +{ + return REALLOC(ptr, size); +} + +void XMLCALL +XML_MemFree(XML_Parser parser, void *ptr) +{ + FREE(ptr); +} + +void XMLCALL +XML_DefaultCurrent(XML_Parser parser) +{ + if (defaultHandler) { + if (openInternalEntities) + reportDefault(parser, + internalEncoding, + openInternalEntities->internalEventPtr, + openInternalEntities->internalEventEndPtr); + else + reportDefault(parser, encoding, eventPtr, eventEndPtr); + } +} + +const XML_LChar * XMLCALL +XML_ErrorString(enum XML_Error code) +{ + static const XML_LChar* const message[] = { + 0, + XML_L("out of memory"), + XML_L("syntax error"), + XML_L("no element found"), + XML_L("not well-formed (invalid token)"), + XML_L("unclosed token"), + XML_L("partial character"), + XML_L("mismatched tag"), + XML_L("duplicate attribute"), + XML_L("junk after document element"), + XML_L("illegal parameter entity reference"), + XML_L("undefined entity"), + XML_L("recursive entity reference"), + XML_L("asynchronous entity"), + XML_L("reference to invalid character number"), + XML_L("reference to binary entity"), + XML_L("reference to external entity in attribute"), + XML_L("XML or text declaration not at start of entity"), + XML_L("unknown encoding"), + XML_L("encoding specified in XML declaration is incorrect"), + XML_L("unclosed CDATA section"), + XML_L("error in processing external entity reference"), + XML_L("document is not standalone"), + XML_L("unexpected parser state - please send a bug report"), + XML_L("entity declared in parameter entity"), + XML_L("requested feature requires XML_DTD support in Expat"), + XML_L("cannot change setting once parsing has begun"), + XML_L("unbound prefix"), + XML_L("must not undeclare prefix"), + XML_L("incomplete markup in parameter entity"), + XML_L("XML declaration not well-formed"), + XML_L("text declaration not well-formed"), + XML_L("illegal character(s) in public id"), + XML_L("parser suspended"), + XML_L("parser not suspended"), + XML_L("parsing aborted"), + XML_L("parsing finished"), + XML_L("cannot suspend in external parameter entity"), + XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"), + XML_L("reserved prefix (xmlns) must not be declared or undeclared"), + XML_L("prefix must not be bound to one of the reserved namespace names") + }; + if (code > 0 && code < sizeof(message)/sizeof(message[0])) + return message[code]; + return NULL; +} + +const XML_LChar * XMLCALL +XML_ExpatVersion(void) { + + /* V1 is used to string-ize the version number. However, it would + string-ize the actual version macro *names* unless we get them + substituted before being passed to V1. CPP is defined to expand + a macro, then rescan for more expansions. Thus, we use V2 to expand + the version macros, then CPP will expand the resulting V1() macro + with the correct numerals. */ + /* ### I'm assuming cpp is portable in this respect... */ + +#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c) +#define V2(a,b,c) XML_L("expat_")V1(a,b,c) + + return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION); + +#undef V1 +#undef V2 +} + +XML_Expat_Version XMLCALL +XML_ExpatVersionInfo(void) +{ + XML_Expat_Version version; + + version.major = XML_MAJOR_VERSION; + version.minor = XML_MINOR_VERSION; + version.micro = XML_MICRO_VERSION; + + return version; +} + +const XML_Feature * XMLCALL +XML_GetFeatureList(void) +{ + static const XML_Feature features[] = { + {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"), + sizeof(XML_Char)}, + {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"), + sizeof(XML_LChar)}, +#ifdef XML_UNICODE + {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0}, +#endif +#ifdef XML_UNICODE_WCHAR_T + {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0}, +#endif +#ifdef XML_DTD + {XML_FEATURE_DTD, XML_L("XML_DTD"), 0}, +#endif +#ifdef XML_CONTEXT_BYTES + {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"), + XML_CONTEXT_BYTES}, +#endif +#ifdef XML_MIN_SIZE + {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0}, +#endif +#ifdef XML_NS + {XML_FEATURE_NS, XML_L("XML_NS"), 0}, +#endif +#ifdef XML_LARGE_SIZE + {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0}, +#endif +#ifdef XML_ATTR_INFO + {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0}, +#endif + {XML_FEATURE_END, NULL, 0} + }; + + return features; +} + +/* Initially tag->rawName always points into the parse buffer; + for those TAG instances opened while the current parse buffer was + processed, and not yet closed, we need to store tag->rawName in a more + permanent location, since the parse buffer is about to be discarded. +*/ +static XML_Bool +storeRawNames(XML_Parser parser) +{ + TAG *tag = tagStack; + while (tag) { + int bufSize; + int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1); + char *rawNameBuf = tag->buf + nameLen; + /* Stop if already stored. Since tagStack is a stack, we can stop + at the first entry that has already been copied; everything + below it in the stack is already been accounted for in a + previous call to this function. + */ + if (tag->rawName == rawNameBuf) + break; + /* For re-use purposes we need to ensure that the + size of tag->buf is a multiple of sizeof(XML_Char). + */ + bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)); + if (bufSize > tag->bufEnd - tag->buf) { + char *temp = (char *)REALLOC(tag->buf, bufSize); + if (temp == NULL) + return XML_FALSE; + /* if tag->name.str points to tag->buf (only when namespace + processing is off) then we have to update it + */ + if (tag->name.str == (XML_Char *)tag->buf) + tag->name.str = (XML_Char *)temp; + /* if tag->name.localPart is set (when namespace processing is on) + then update it as well, since it will always point into tag->buf + */ + if (tag->name.localPart) + tag->name.localPart = (XML_Char *)temp + (tag->name.localPart - + (XML_Char *)tag->buf); + tag->buf = temp; + tag->bufEnd = temp + bufSize; + rawNameBuf = temp + nameLen; + } + memcpy(rawNameBuf, tag->rawName, tag->rawNameLength); + tag->rawName = rawNameBuf; + tag = tag->parent; + } + return XML_TRUE; +} + +static enum XML_Error PTRCALL +contentProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doContent(parser, 0, encoding, start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result == XML_ERROR_NONE) { + if (!storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + processor = externalEntityInitProcessor2; + return externalEntityInitProcessor2(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor2(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + const char *next = start; /* XmlContentTok doesn't always set the last arg */ + int tok = XmlContentTok(encoding, start, end, &next); + switch (tok) { + case XML_TOK_BOM: + /* If we are at the end of the buffer, this would cause the next stage, + i.e. externalEntityInitProcessor3, to pass control directly to + doContent (by detecting XML_TOK_NONE) without processing any xml text + declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent. + */ + if (next == end && !ps_finalBuffer) { + *endPtr = next; + return XML_ERROR_NONE; + } + start = next; + break; + case XML_TOK_PARTIAL: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_PARTIAL_CHAR; + } + processor = externalEntityInitProcessor3; + return externalEntityInitProcessor3(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor3(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + int tok; + const char *next = start; /* XmlContentTok doesn't always set the last arg */ + eventPtr = start; + tok = XmlContentTok(encoding, start, end, &next); + eventEndPtr = next; + + switch (tok) { + case XML_TOK_XML_DECL: + { + enum XML_Error result; + result = processXmlDecl(parser, 1, start, next); + if (result != XML_ERROR_NONE) + return result; + switch (ps_parsing) { + case XML_SUSPENDED: + *endPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: + start = next; + } + } + break; + case XML_TOK_PARTIAL: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + } + processor = externalEntityContentProcessor; + tagLevel = 1; + return externalEntityContentProcessor(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityContentProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doContent(parser, 1, encoding, start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result == XML_ERROR_NONE) { + if (!storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; +} + +static enum XML_Error +doContent(XML_Parser parser, + int startTagLevel, + const ENCODING *enc, + const char *s, + const char *end, + const char **nextPtr, + XML_Bool haveMore) +{ + /* save one level of indirection */ + DTD * const dtd = _dtd; + + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + + for (;;) { + const char *next = s; /* XmlContentTok doesn't always set the last arg */ + int tok = XmlContentTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_TRAILING_CR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + *eventEndPP = end; + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, end); + /* We are at the end of the final buffer, should we check for + XML_SUSPENDED, XML_FINISHED? + */ + if (startTagLevel == 0) + return XML_ERROR_NO_ELEMENTS; + if (tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + *nextPtr = end; + return XML_ERROR_NONE; + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (startTagLevel > 0) { + if (tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_NO_ELEMENTS; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (ch) { + if (characterDataHandler) + characterDataHandler(handlerArg, &ch, 1); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + name = poolStoreString(&dtd->pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); + poolDiscard(&dtd->pool); + /* First, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal, + otherwise call the skipped entity or default handler. + */ + if (!dtd->hasParamEntityRefs || dtd->standalone) { + if (!entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (!entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } + else if (!entity) { + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, name, 0); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->notation) + return XML_ERROR_BINARY_ENTITY_REF; + if (entity->textPtr) { + enum XML_Error result; + if (!defaultExpandInternalEntities) { + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, entity->name, 0); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + result = processInternalEntity(parser, entity, XML_FALSE); + if (result != XML_ERROR_NONE) + return result; + } + else if (externalEntityRefHandler) { + const XML_Char *context; + entity->open = XML_TRUE; + context = getContext(parser); + entity->open = XML_FALSE; + if (!context) + return XML_ERROR_NO_MEMORY; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + context, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + poolDiscard(&tempPool); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + case XML_TOK_START_TAG_NO_ATTS: + /* fall through */ + case XML_TOK_START_TAG_WITH_ATTS: + { + TAG *tag; + enum XML_Error result; + XML_Char *toPtr; + if (freeTagList) { + tag = freeTagList; + freeTagList = freeTagList->parent; + } + else { + tag = (TAG *)MALLOC(sizeof(TAG)); + if (!tag) + return XML_ERROR_NO_MEMORY; + tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE); + if (!tag->buf) { + FREE(tag); + return XML_ERROR_NO_MEMORY; + } + tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE; + } + tag->bindings = NULL; + tag->parent = tagStack; + tagStack = tag; + tag->name.localPart = NULL; + tag->name.prefix = NULL; + tag->rawName = s + enc->minBytesPerChar; + tag->rawNameLength = XmlNameLength(enc, tag->rawName); + ++tagLevel; + { + const char *rawNameEnd = tag->rawName + tag->rawNameLength; + const char *fromPtr = tag->rawName; + toPtr = (XML_Char *)tag->buf; + for (;;) { + int bufSize; + int convLen; + XmlConvert(enc, + &fromPtr, rawNameEnd, + (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1); + convLen = (int)(toPtr - (XML_Char *)tag->buf); + if (fromPtr == rawNameEnd) { + tag->name.strLen = convLen; + break; + } + bufSize = (int)(tag->bufEnd - tag->buf) << 1; + { + char *temp = (char *)REALLOC(tag->buf, bufSize); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + tag->buf = temp; + tag->bufEnd = temp + bufSize; + toPtr = (XML_Char *)temp + convLen; + } + } + } + tag->name.str = (XML_Char *)tag->buf; + *toPtr = XML_T('\0'); + result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings)); + if (result) + return result; + if (startElementHandler) + startElementHandler(handlerArg, tag->name.str, + (const XML_Char **)atts); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + poolClear(&tempPool); + break; + } + case XML_TOK_EMPTY_ELEMENT_NO_ATTS: + /* fall through */ + case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: + { + const char *rawName = s + enc->minBytesPerChar; + enum XML_Error result; + BINDING *bindings = NULL; + XML_Bool noElmHandlers = XML_TRUE; + TAG_NAME name; + name.str = poolStoreString(&tempPool, enc, rawName, + rawName + XmlNameLength(enc, rawName)); + if (!name.str) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + result = storeAtts(parser, enc, s, &name, &bindings); + if (result) + return result; + poolFinish(&tempPool); + if (startElementHandler) { + startElementHandler(handlerArg, name.str, (const XML_Char **)atts); + noElmHandlers = XML_FALSE; + } + if (endElementHandler) { + if (startElementHandler) + *eventPP = *eventEndPP; + endElementHandler(handlerArg, name.str); + noElmHandlers = XML_FALSE; + } + if (noElmHandlers && defaultHandler) + reportDefault(parser, enc, s, next); + poolClear(&tempPool); + while (bindings) { + BINDING *b = bindings; + if (endNamespaceDeclHandler) + endNamespaceDeclHandler(handlerArg, b->prefix->name); + bindings = bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } + } + if (tagLevel == 0) + return epilogProcessor(parser, next, end, nextPtr); + break; + case XML_TOK_END_TAG: + if (tagLevel == startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + else { + int len; + const char *rawName; + TAG *tag = tagStack; + tagStack = tag->parent; + tag->parent = freeTagList; + freeTagList = tag; + rawName = s + enc->minBytesPerChar*2; + len = XmlNameLength(enc, rawName); + if (len != tag->rawNameLength + || memcmp(tag->rawName, rawName, len) != 0) { + *eventPP = rawName; + return XML_ERROR_TAG_MISMATCH; + } + --tagLevel; + if (endElementHandler) { + const XML_Char *localPart; + const XML_Char *prefix; + XML_Char *uri; + localPart = tag->name.localPart; + if (ns && localPart) { + /* localPart and prefix may have been overwritten in + tag->name.str, since this points to the binding->uri + buffer which gets re-used; so we have to add them again + */ + uri = (XML_Char *)tag->name.str + tag->name.uriLen; + /* don't need to check for space - already done in storeAtts() */ + while (*localPart) *uri++ = *localPart++; + prefix = (XML_Char *)tag->name.prefix; + if (ns_triplets && prefix) { + *uri++ = namespaceSeparator; + while (*prefix) *uri++ = *prefix++; + } + *uri = XML_T('\0'); + } + endElementHandler(handlerArg, tag->name.str); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + while (tag->bindings) { + BINDING *b = tag->bindings; + if (endNamespaceDeclHandler) + endNamespaceDeclHandler(handlerArg, b->prefix->name); + tag->bindings = tag->bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } + if (tagLevel == 0) + return epilogProcessor(parser, next, end, nextPtr); + } + break; + case XML_TOK_CHAR_REF: + { + int n = XmlCharRefNumber(enc, s); + if (n < 0) + return XML_ERROR_BAD_CHAR_REF; + if (characterDataHandler) { + XML_Char buf[XML_ENCODE_MAX]; + characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + } + break; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_CDATA_SECT_OPEN: + { + enum XML_Error result; + if (startCdataSectionHandler) + startCdataSectionHandler(handlerArg); +#if 0 + /* Suppose you doing a transformation on a document that involves + changing only the character data. You set up a defaultHandler + and a characterDataHandler. The defaultHandler simply copies + characters through. The characterDataHandler does the + transformation and writes the characters out escaping them as + necessary. This case will fail to work if we leave out the + following two lines (because & and < inside CDATA sections will + be incorrectly escaped). + + However, now we have a start/endCdataSectionHandler, so it seems + easier to let the user deal with this. + */ + else if (characterDataHandler) + characterDataHandler(handlerArg, dataBuf, 0); +#endif + else if (defaultHandler) + reportDefault(parser, enc, s, next); + result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore); + if (result != XML_ERROR_NONE) + return result; + else if (!next) { + processor = cdataSectionProcessor; + return result; + } + } + break; + case XML_TOK_TRAILING_RSQB: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); + characterDataHandler(handlerArg, dataBuf, + (int)(dataPtr - (ICHAR *)dataBuf)); + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (int)((XML_Char *)end - (XML_Char *)s)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, end); + /* We are at the end of the final buffer, should we check for + XML_SUSPENDED, XML_FINISHED? + */ + if (startTagLevel == 0) { + *eventPP = end; + return XML_ERROR_NO_ELEMENTS; + } + if (tagLevel != startTagLevel) { + *eventPP = end; + return XML_ERROR_ASYNC_ENTITY; + } + *nextPtr = end; + return XML_ERROR_NONE; + case XML_TOK_DATA_CHARS: + { + XML_CharacterDataHandler charDataHandler = characterDataHandler; + if (charDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = s; + charDataHandler(handlerArg, dataBuf, + (int)(dataPtr - (ICHAR *)dataBuf)); + if (s == next) + break; + *eventPP = s; + } + } + else + charDataHandler(handlerArg, + (XML_Char *)s, + (int)((XML_Char *)next - (XML_Char *)s)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + } + break; + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + default: + if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + *eventPP = s = next; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: ; + } + } + /* not reached */ +} + +/* Precondition: all arguments must be non-NULL; + Purpose: + - normalize attributes + - check attributes for well-formedness + - generate namespace aware attribute names (URI, prefix) + - build list of attributes for startElementHandler + - default attributes + - process namespace declarations (check and report them) + - generate namespace aware element name (URI, prefix) +*/ +static enum XML_Error +storeAtts(XML_Parser parser, const ENCODING *enc, + const char *attStr, TAG_NAME *tagNamePtr, + BINDING **bindingsPtr) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + ELEMENT_TYPE *elementType; + int nDefaultAtts; + const XML_Char **appAtts; /* the attribute list for the application */ + int attIndex = 0; + int prefixLen; + int i; + int n; + XML_Char *uri; + int nPrefixes = 0; + BINDING *binding; + const XML_Char *localPart; + + /* lookup the element type name */ + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0); + if (!elementType) { + const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); + if (!name) + return XML_ERROR_NO_MEMORY; + elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, + sizeof(ELEMENT_TYPE)); + if (!elementType) + return XML_ERROR_NO_MEMORY; + if (ns && !setElementTypePrefix(parser, elementType)) + return XML_ERROR_NO_MEMORY; + } + nDefaultAtts = elementType->nDefaultAtts; + + /* get the attributes from the tokenizer */ + n = XmlGetAttributes(enc, attStr, attsSize, atts); + if (n + nDefaultAtts > attsSize) { + int oldAttsSize = attsSize; + ATTRIBUTE *temp; +#ifdef XML_ATTR_INFO + XML_AttrInfo *temp2; +#endif + attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; + temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE)); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + atts = temp; +#ifdef XML_ATTR_INFO + temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo)); + if (temp2 == NULL) + return XML_ERROR_NO_MEMORY; + attInfo = temp2; +#endif + if (n > oldAttsSize) + XmlGetAttributes(enc, attStr, n, atts); + } + + appAtts = (const XML_Char **)atts; + for (i = 0; i < n; i++) { + ATTRIBUTE *currAtt = &atts[i]; +#ifdef XML_ATTR_INFO + XML_AttrInfo *currAttInfo = &attInfo[i]; +#endif + /* add the name and value to the attribute list */ + ATTRIBUTE_ID *attId = getAttributeId(parser, enc, currAtt->name, + currAtt->name + + XmlNameLength(enc, currAtt->name)); + if (!attId) + return XML_ERROR_NO_MEMORY; +#ifdef XML_ATTR_INFO + currAttInfo->nameStart = parseEndByteIndex - (parseEndPtr - currAtt->name); + currAttInfo->nameEnd = currAttInfo->nameStart + + XmlNameLength(enc, currAtt->name); + currAttInfo->valueStart = parseEndByteIndex - + (parseEndPtr - currAtt->valuePtr); + currAttInfo->valueEnd = parseEndByteIndex - (parseEndPtr - currAtt->valueEnd); +#endif + /* Detect duplicate attributes by their QNames. This does not work when + namespace processing is turned on and different prefixes for the same + namespace are used. For this case we have a check further down. + */ + if ((attId->name)[-1]) { + if (enc == encoding) + eventPtr = atts[i].name; + return XML_ERROR_DUPLICATE_ATTRIBUTE; + } + (attId->name)[-1] = 1; + appAtts[attIndex++] = attId->name; + if (!atts[i].normalized) { + enum XML_Error result; + XML_Bool isCdata = XML_TRUE; + + /* figure out whether declared as other than CDATA */ + if (attId->maybeTokenized) { + int j; + for (j = 0; j < nDefaultAtts; j++) { + if (attId == elementType->defaultAtts[j].id) { + isCdata = elementType->defaultAtts[j].isCdata; + break; + } + } + } + + /* normalize the attribute value */ + result = storeAttributeValue(parser, enc, isCdata, + atts[i].valuePtr, atts[i].valueEnd, + &tempPool); + if (result) + return result; + appAtts[attIndex] = poolStart(&tempPool); + poolFinish(&tempPool); + } + else { + /* the value did not need normalizing */ + appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr, + atts[i].valueEnd); + if (appAtts[attIndex] == 0) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + } + /* handle prefixed attribute names */ + if (attId->prefix) { + if (attId->xmlns) { + /* deal with namespace declarations here */ + enum XML_Error result = addBinding(parser, attId->prefix, attId, + appAtts[attIndex], bindingsPtr); + if (result) + return result; + --attIndex; + } + else { + /* deal with other prefixed names later */ + attIndex++; + nPrefixes++; + (attId->name)[-1] = 2; + } + } + else + attIndex++; + } + + /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */ + nSpecifiedAtts = attIndex; + if (elementType->idAtt && (elementType->idAtt->name)[-1]) { + for (i = 0; i < attIndex; i += 2) + if (appAtts[i] == elementType->idAtt->name) { + idAttIndex = i; + break; + } + } + else + idAttIndex = -1; + + /* do attribute defaulting */ + for (i = 0; i < nDefaultAtts; i++) { + const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i; + if (!(da->id->name)[-1] && da->value) { + if (da->id->prefix) { + if (da->id->xmlns) { + enum XML_Error result = addBinding(parser, da->id->prefix, da->id, + da->value, bindingsPtr); + if (result) + return result; + } + else { + (da->id->name)[-1] = 2; + nPrefixes++; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } + else { + (da->id->name)[-1] = 1; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } + } + appAtts[attIndex] = 0; + + /* expand prefixed attribute names, check for duplicates, + and clear flags that say whether attributes were specified */ + i = 0; + if (nPrefixes) { + int j; /* hash table index */ + unsigned long version = nsAttsVersion; + int nsAttsSize = (int)1 << nsAttsPower; + /* size of hash table must be at least 2 * (# of prefixed attributes) */ + if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */ + NS_ATT *temp; + /* hash table size must also be a power of 2 and >= 8 */ + while (nPrefixes >> nsAttsPower++); + if (nsAttsPower < 3) + nsAttsPower = 3; + nsAttsSize = (int)1 << nsAttsPower; + temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT)); + if (!temp) + return XML_ERROR_NO_MEMORY; + nsAtts = temp; + version = 0; /* force re-initialization of nsAtts hash table */ + } + /* using a version flag saves us from initializing nsAtts every time */ + if (!version) { /* initialize version flags when version wraps around */ + version = INIT_ATTS_VERSION; + for (j = nsAttsSize; j != 0; ) + nsAtts[--j].version = version; + } + nsAttsVersion = --version; + + /* expand prefixed names and check for duplicates */ + for (; i < attIndex; i += 2) { + const XML_Char *s = appAtts[i]; + if (s[-1] == 2) { /* prefixed */ + ATTRIBUTE_ID *id; + const BINDING *b; + unsigned long uriHash = hash_secret_salt; + ((XML_Char *)s)[-1] = 0; /* clear flag */ + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); + b = id->prefix->binding; + if (!b) + return XML_ERROR_UNBOUND_PREFIX; + + /* as we expand the name we also calculate its hash value */ + for (j = 0; j < b->uriLen; j++) { + const XML_Char c = b->uri[j]; + if (!poolAppendChar(&tempPool, c)) + return XML_ERROR_NO_MEMORY; + uriHash = CHAR_HASH(uriHash, c); + } + while (*s++ != XML_T(ASCII_COLON)) + ; + do { /* copies null terminator */ + const XML_Char c = *s; + if (!poolAppendChar(&tempPool, *s)) + return XML_ERROR_NO_MEMORY; + uriHash = CHAR_HASH(uriHash, c); + } while (*s++); + + { /* Check hash table for duplicate of expanded name (uriName). + Derived from code in lookup(parser, HASH_TABLE *table, ...). + */ + unsigned char step = 0; + unsigned long mask = nsAttsSize - 1; + j = uriHash & mask; /* index into hash table */ + while (nsAtts[j].version == version) { + /* for speed we compare stored hash values first */ + if (uriHash == nsAtts[j].hash) { + const XML_Char *s1 = poolStart(&tempPool); + const XML_Char *s2 = nsAtts[j].uriName; + /* s1 is null terminated, but not s2 */ + for (; *s1 == *s2 && *s1 != 0; s1++, s2++); + if (*s1 == 0) + return XML_ERROR_DUPLICATE_ATTRIBUTE; + } + if (!step) + step = PROBE_STEP(uriHash, mask, nsAttsPower); + j < step ? (j += nsAttsSize - step) : (j -= step); + } + } + + if (ns_triplets) { /* append namespace separator and prefix */ + tempPool.ptr[-1] = namespaceSeparator; + s = b->prefix->name; + do { + if (!poolAppendChar(&tempPool, *s)) + return XML_ERROR_NO_MEMORY; + } while (*s++); + } + + /* store expanded name in attribute list */ + s = poolStart(&tempPool); + poolFinish(&tempPool); + appAtts[i] = s; + + /* fill empty slot with new version, uriName and hash value */ + nsAtts[j].version = version; + nsAtts[j].hash = uriHash; + nsAtts[j].uriName = s; + + if (!--nPrefixes) { + i += 2; + break; + } + } + else /* not prefixed */ + ((XML_Char *)s)[-1] = 0; /* clear flag */ + } + } + /* clear flags for the remaining attributes */ + for (; i < attIndex; i += 2) + ((XML_Char *)(appAtts[i]))[-1] = 0; + for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding) + binding->attId->name[-1] = 0; + + if (!ns) + return XML_ERROR_NONE; + + /* expand the element type name */ + if (elementType->prefix) { + binding = elementType->prefix->binding; + if (!binding) + return XML_ERROR_UNBOUND_PREFIX; + localPart = tagNamePtr->str; + while (*localPart++ != XML_T(ASCII_COLON)) + ; + } + else if (dtd->defaultPrefix.binding) { + binding = dtd->defaultPrefix.binding; + localPart = tagNamePtr->str; + } + else + return XML_ERROR_NONE; + prefixLen = 0; + if (ns_triplets && binding->prefix->name) { + for (; binding->prefix->name[prefixLen++];) + ; /* prefixLen includes null terminator */ + } + tagNamePtr->localPart = localPart; + tagNamePtr->uriLen = binding->uriLen; + tagNamePtr->prefix = binding->prefix->name; + tagNamePtr->prefixLen = prefixLen; + for (i = 0; localPart[i++];) + ; /* i includes null terminator */ + n = i + binding->uriLen + prefixLen; + if (n > binding->uriAlloc) { + TAG *p; + uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char)); + if (!uri) + return XML_ERROR_NO_MEMORY; + binding->uriAlloc = n + EXPAND_SPARE; + memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char)); + for (p = tagStack; p; p = p->parent) + if (p->name.str == binding->uri) + p->name.str = uri; + FREE(binding->uri); + binding->uri = uri; + } + /* if namespaceSeparator != '\0' then uri includes it already */ + uri = binding->uri + binding->uriLen; + memcpy(uri, localPart, i * sizeof(XML_Char)); + /* we always have a namespace separator between localPart and prefix */ + if (prefixLen) { + uri += i - 1; + *uri = namespaceSeparator; /* replace null terminator */ + memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char)); + } + tagNamePtr->str = binding->uri; + return XML_ERROR_NONE; +} + +/* addBinding() overwrites the value of prefix->binding without checking. + Therefore one must keep track of the old value outside of addBinding(). +*/ +static enum XML_Error +addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, + const XML_Char *uri, BINDING **bindingsPtr) +{ + static const XML_Char xmlNamespace[] = { + ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH, + ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, + ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, + ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8, ASCII_SLASH, + ASCII_n, ASCII_a, ASCII_m, ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c, + ASCII_e, '\0' + }; + static const int xmlLen = + (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1; + static const XML_Char xmlnsNamespace[] = { + ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH, + ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, + ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_2, ASCII_0, ASCII_0, + ASCII_0, ASCII_SLASH, ASCII_x, ASCII_m, ASCII_l, ASCII_n, ASCII_s, + ASCII_SLASH, '\0' + }; + static const int xmlnsLen = + (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1; + + XML_Bool mustBeXML = XML_FALSE; + XML_Bool isXML = XML_TRUE; + XML_Bool isXMLNS = XML_TRUE; + + BINDING *b; + int len; + + /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */ + if (*uri == XML_T('\0') && prefix->name) + return XML_ERROR_UNDECLARING_PREFIX; + + if (prefix->name + && prefix->name[0] == XML_T(ASCII_x) + && prefix->name[1] == XML_T(ASCII_m) + && prefix->name[2] == XML_T(ASCII_l)) { + + /* Not allowed to bind xmlns */ + if (prefix->name[3] == XML_T(ASCII_n) + && prefix->name[4] == XML_T(ASCII_s) + && prefix->name[5] == XML_T('\0')) + return XML_ERROR_RESERVED_PREFIX_XMLNS; + + if (prefix->name[3] == XML_T('\0')) + mustBeXML = XML_TRUE; + } + + for (len = 0; uri[len]; len++) { + if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len])) + isXML = XML_FALSE; + + if (!mustBeXML && isXMLNS + && (len > xmlnsLen || uri[len] != xmlnsNamespace[len])) + isXMLNS = XML_FALSE; + } + isXML = isXML && len == xmlLen; + isXMLNS = isXMLNS && len == xmlnsLen; + + if (mustBeXML != isXML) + return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML + : XML_ERROR_RESERVED_NAMESPACE_URI; + + if (isXMLNS) + return XML_ERROR_RESERVED_NAMESPACE_URI; + + if (namespaceSeparator) + len++; + if (freeBindingList) { + b = freeBindingList; + if (len > b->uriAlloc) { + XML_Char *temp = (XML_Char *)REALLOC(b->uri, + sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + b->uri = temp; + b->uriAlloc = len + EXPAND_SPARE; + } + freeBindingList = b->nextTagBinding; + } + else { + b = (BINDING *)MALLOC(sizeof(BINDING)); + if (!b) + return XML_ERROR_NO_MEMORY; + b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (!b->uri) { + FREE(b); + return XML_ERROR_NO_MEMORY; + } + b->uriAlloc = len + EXPAND_SPARE; + } + b->uriLen = len; + memcpy(b->uri, uri, len * sizeof(XML_Char)); + if (namespaceSeparator) + b->uri[len - 1] = namespaceSeparator; + b->prefix = prefix; + b->attId = attId; + b->prevPrefixBinding = prefix->binding; + /* NULL binding when default namespace undeclared */ + if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix) + prefix->binding = NULL; + else + prefix->binding = b; + b->nextTagBinding = *bindingsPtr; + *bindingsPtr = b; + /* if attId == NULL then we are not starting a namespace scope */ + if (attId && startNamespaceDeclHandler) + startNamespaceDeclHandler(handlerArg, prefix->name, + prefix->binding ? uri : 0); + return XML_ERROR_NONE; +} + +/* The idea here is to avoid using stack for each CDATA section when + the whole file is parsed with one call. +*/ +static enum XML_Error PTRCALL +cdataSectionProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doCdataSection(parser, encoding, &start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result != XML_ERROR_NONE) + return result; + if (start) { + if (parentParser) { /* we are parsing an external entity */ + processor = externalEntityContentProcessor; + return externalEntityContentProcessor(parser, start, end, endPtr); + } + else { + processor = contentProcessor; + return contentProcessor(parser, start, end, endPtr); + } + } + return result; +} + +/* startPtr gets set to non-null if the section is closed, and to null if + the section is not yet closed. +*/ +static enum XML_Error +doCdataSection(XML_Parser parser, + const ENCODING *enc, + const char **startPtr, + const char *end, + const char **nextPtr, + XML_Bool haveMore) +{ + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + *eventPP = s; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + *startPtr = NULL; + + for (;;) { + const char *next; + int tok = XmlCdataSectionTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_CDATA_SECT_CLOSE: + if (endCdataSectionHandler) + endCdataSectionHandler(handlerArg); +#if 0 + /* see comment under XML_TOK_CDATA_SECT_OPEN */ + else if (characterDataHandler) + characterDataHandler(handlerArg, dataBuf, 0); +#endif + else if (defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + *nextPtr = next; + if (ps_parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + else + return XML_ERROR_NONE; + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_DATA_CHARS: + { + XML_CharacterDataHandler charDataHandler = characterDataHandler; + if (charDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = next; + charDataHandler(handlerArg, dataBuf, + (int)(dataPtr - (ICHAR *)dataBuf)); + if (s == next) + break; + *eventPP = s; + } + } + else + charDataHandler(handlerArg, + (XML_Char *)s, + (int)((XML_Char *)next - (XML_Char *)s)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + } + break; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_CDATA_SECTION; + default: + *eventPP = next; + return XML_ERROR_UNEXPECTED_STATE; + } + + *eventPP = s = next; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: ; + } + } + /* not reached */ +} + +#ifdef XML_DTD + +/* The idea here is to avoid using stack for each IGNORE section when + the whole file is parsed with one call. +*/ +static enum XML_Error PTRCALL +ignoreSectionProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doIgnoreSection(parser, encoding, &start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result != XML_ERROR_NONE) + return result; + if (start) { + processor = prologProcessor; + return prologProcessor(parser, start, end, endPtr); + } + return result; +} + +/* startPtr gets set to non-null is the section is closed, and to null + if the section is not yet closed. +*/ +static enum XML_Error +doIgnoreSection(XML_Parser parser, + const ENCODING *enc, + const char **startPtr, + const char *end, + const char **nextPtr, + XML_Bool haveMore) +{ + const char *next; + int tok; + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + *eventPP = s; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + *startPtr = NULL; + tok = XmlIgnoreSectionTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_IGNORE_SECT: + if (defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + *nextPtr = next; + if (ps_parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + else + return XML_ERROR_NONE; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */ + default: + *eventPP = next; + return XML_ERROR_UNEXPECTED_STATE; + } + /* not reached */ +} + +#endif /* XML_DTD */ + +static enum XML_Error +initializeEncoding(XML_Parser parser) +{ + const char *s; +#ifdef XML_UNICODE + char encodingBuf[128]; + if (!protocolEncodingName) + s = NULL; + else { + int i; + for (i = 0; protocolEncodingName[i]; i++) { + if (i == sizeof(encodingBuf) - 1 + || (protocolEncodingName[i] & ~0x7f) != 0) { + encodingBuf[0] = '\0'; + break; + } + encodingBuf[i] = (char)protocolEncodingName[i]; + } + encodingBuf[i] = '\0'; + s = encodingBuf; + } +#else + s = protocolEncodingName; +#endif + if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s)) + return XML_ERROR_NONE; + return handleUnknownEncoding(parser, protocolEncodingName); +} + +static enum XML_Error +processXmlDecl(XML_Parser parser, int isGeneralTextEntity, + const char *s, const char *next) +{ + const char *encodingName = NULL; + const XML_Char *storedEncName = NULL; + const ENCODING *newEncoding = NULL; + const char *version = NULL; + const char *versionend; + const XML_Char *storedversion = NULL; + int standalone = -1; + if (!(ns + ? XmlParseXmlDeclNS + : XmlParseXmlDecl)(isGeneralTextEntity, + encoding, + s, + next, + &eventPtr, + &version, + &versionend, + &encodingName, + &newEncoding, + &standalone)) { + if (isGeneralTextEntity) + return XML_ERROR_TEXT_DECL; + else + return XML_ERROR_XML_DECL; + } + if (!isGeneralTextEntity && standalone == 1) { + _dtd->standalone = XML_TRUE; +#ifdef XML_DTD + if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE) + paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif /* XML_DTD */ + } + if (xmlDeclHandler) { + if (encodingName != NULL) { + storedEncName = poolStoreString(&temp2Pool, + encoding, + encodingName, + encodingName + + XmlNameLength(encoding, encodingName)); + if (!storedEncName) + return XML_ERROR_NO_MEMORY; + poolFinish(&temp2Pool); + } + if (version) { + storedversion = poolStoreString(&temp2Pool, + encoding, + version, + versionend - encoding->minBytesPerChar); + if (!storedversion) + return XML_ERROR_NO_MEMORY; + } + xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone); + } + else if (defaultHandler) + reportDefault(parser, encoding, s, next); + if (protocolEncodingName == NULL) { + if (newEncoding) { + if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) { + eventPtr = encodingName; + return XML_ERROR_INCORRECT_ENCODING; + } + encoding = newEncoding; + } + else if (encodingName) { + enum XML_Error result; + if (!storedEncName) { + storedEncName = poolStoreString( + &temp2Pool, encoding, encodingName, + encodingName + XmlNameLength(encoding, encodingName)); + if (!storedEncName) + return XML_ERROR_NO_MEMORY; + } + result = handleUnknownEncoding(parser, storedEncName); + poolClear(&temp2Pool); + if (result == XML_ERROR_UNKNOWN_ENCODING) + eventPtr = encodingName; + return result; + } + } + + if (storedEncName || storedversion) + poolClear(&temp2Pool); + + return XML_ERROR_NONE; +} + +static enum XML_Error +handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) +{ + if (unknownEncodingHandler) { + XML_Encoding info; + int i; + for (i = 0; i < 256; i++) + info.map[i] = -1; + info.convert = NULL; + info.data = NULL; + info.release = NULL; + if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName, + &info)) { + ENCODING *enc; + unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding()); + if (!unknownEncodingMem) { + if (info.release) + info.release(info.data); + return XML_ERROR_NO_MEMORY; + } + enc = (ns + ? XmlInitUnknownEncodingNS + : XmlInitUnknownEncoding)(unknownEncodingMem, + info.map, + info.convert, + info.data); + if (enc) { + unknownEncodingData = info.data; + unknownEncodingRelease = info.release; + encoding = enc; + return XML_ERROR_NONE; + } + } + if (info.release != NULL) + info.release(info.data); + } + return XML_ERROR_UNKNOWN_ENCODING; +} + +static enum XML_Error PTRCALL +prologInitProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + processor = prologProcessor; + return prologProcessor(parser, s, end, nextPtr); +} + +#ifdef XML_DTD + +static enum XML_Error PTRCALL +externalParEntInitProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + + /* we know now that XML_Parse(Buffer) has been called, + so we consider the external parameter entity read */ + _dtd->paramEntityRead = XML_TRUE; + + if (prologState.inEntityValue) { + processor = entityValueInitProcessor; + return entityValueInitProcessor(parser, s, end, nextPtr); + } + else { + processor = externalParEntProcessor; + return externalParEntProcessor(parser, s, end, nextPtr); + } +} + +static enum XML_Error PTRCALL +entityValueInitProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + int tok; + const char *start = s; + const char *next = start; + eventPtr = start; + + for (;;) { + tok = XmlPrologTok(encoding, start, end, &next); + eventEndPtr = next; + if (tok <= 0) { + if (!ps_finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + /* found end of entity value - can store it now */ + return storeEntityValue(parser, encoding, s, end); + } + else if (tok == XML_TOK_XML_DECL) { + enum XML_Error result; + result = processXmlDecl(parser, 0, start, next); + if (result != XML_ERROR_NONE) + return result; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: + *nextPtr = next; + } + /* stop scanning for text declaration - we found one */ + processor = entityValueProcessor; + return entityValueProcessor(parser, next, end, nextPtr); + } + /* If we are at the end of the buffer, this would cause XmlPrologTok to + return XML_TOK_NONE on the next call, which would then cause the + function to exit with *nextPtr set to s - that is what we want for other + tokens, but not for the BOM - we would rather like to skip it; + then, when this routine is entered the next time, XmlPrologTok will + return XML_TOK_INVALID, since the BOM is still in the buffer + */ + else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) { + *nextPtr = next; + return XML_ERROR_NONE; + } + start = next; + eventPtr = start; + } +} + +static enum XML_Error PTRCALL +externalParEntProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + const char *next = s; + int tok; + + tok = XmlPrologTok(encoding, s, end, &next); + if (tok <= 0) { + if (!ps_finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + } + /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM. + However, when parsing an external subset, doProlog will not accept a BOM + as valid, and report a syntax error, so we have to skip the BOM + */ + else if (tok == XML_TOK_BOM) { + s = next; + tok = XmlPrologTok(encoding, s, end, &next); + } + + processor = prologProcessor; + return doProlog(parser, encoding, s, end, tok, next, + nextPtr, (XML_Bool)!ps_finalBuffer); +} + +static enum XML_Error PTRCALL +entityValueProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + const char *start = s; + const char *next = s; + const ENCODING *enc = encoding; + int tok; + + for (;;) { + tok = XmlPrologTok(enc, start, end, &next); + if (tok <= 0) { + if (!ps_finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + /* found end of entity value - can store it now */ + return storeEntityValue(parser, enc, s, end); + } + start = next; + } +} + +#endif /* XML_DTD */ + +static enum XML_Error PTRCALL +prologProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + const char *next = s; + int tok = XmlPrologTok(encoding, s, end, &next); + return doProlog(parser, encoding, s, end, tok, next, + nextPtr, (XML_Bool)!ps_finalBuffer); +} + +static enum XML_Error +doProlog(XML_Parser parser, + const ENCODING *enc, + const char *s, + const char *end, + int tok, + const char *next, + const char **nextPtr, + XML_Bool haveMore) +{ +#ifdef XML_DTD + static const XML_Char externalSubsetName[] = { ASCII_HASH , '\0' }; +#endif /* XML_DTD */ + static const XML_Char atypeCDATA[] = + { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; + static const XML_Char atypeID[] = { ASCII_I, ASCII_D, '\0' }; + static const XML_Char atypeIDREF[] = + { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' }; + static const XML_Char atypeIDREFS[] = + { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' }; + static const XML_Char atypeENTITY[] = + { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' }; + static const XML_Char atypeENTITIES[] = { ASCII_E, ASCII_N, + ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' }; + static const XML_Char atypeNMTOKEN[] = { + ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' }; + static const XML_Char atypeNMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T, + ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' }; + static const XML_Char notationPrefix[] = { ASCII_N, ASCII_O, ASCII_T, + ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0' }; + static const XML_Char enumValueSep[] = { ASCII_PIPE, '\0' }; + static const XML_Char enumValueStart[] = { ASCII_LPAREN, '\0' }; + + /* save one level of indirection */ + DTD * const dtd = _dtd; + + const char **eventPP; + const char **eventEndPP; + enum XML_Content_Quant quant; + + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + + for (;;) { + int role; + XML_Bool handleDefault = XML_TRUE; + *eventPP = s; + *eventEndPP = next; + if (tok <= 0) { + if (haveMore && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case -XML_TOK_PROLOG_S: + tok = -tok; + break; + case XML_TOK_NONE: +#ifdef XML_DTD + /* for internal PE NOT referenced between declarations */ + if (enc != encoding && !openInternalEntities->betweenDecl) { + *nextPtr = s; + return XML_ERROR_NONE; + } + /* WFC: PE Between Declarations - must check that PE contains + complete markup, not only for external PEs, but also for + internal PEs if the reference occurs between declarations. + */ + if (isParamEntity || enc != encoding) { + if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc) + == XML_ROLE_ERROR) + return XML_ERROR_INCOMPLETE_PE; + *nextPtr = s; + return XML_ERROR_NONE; + } +#endif /* XML_DTD */ + return XML_ERROR_NO_ELEMENTS; + default: + tok = -tok; + next = end; + break; + } + } + role = XmlTokenRole(&prologState, tok, s, next, enc); + switch (role) { + case XML_ROLE_XML_DECL: + { + enum XML_Error result = processXmlDecl(parser, 0, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = encoding; + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_DOCTYPE_NAME: + if (startDoctypeDeclHandler) { + doctypeName = poolStoreString(&tempPool, enc, s, next); + if (!doctypeName) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + doctypePubid = NULL; + handleDefault = XML_FALSE; + } + doctypeSysid = NULL; /* always initialize to NULL */ + break; + case XML_ROLE_DOCTYPE_INTERNAL_SUBSET: + if (startDoctypeDeclHandler) { + startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid, + doctypePubid, 1); + doctypeName = NULL; + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + break; +#ifdef XML_DTD + case XML_ROLE_TEXT_DECL: + { + enum XML_Error result = processXmlDecl(parser, 1, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = encoding; + handleDefault = XML_FALSE; + } + break; +#endif /* XML_DTD */ + case XML_ROLE_DOCTYPE_PUBLIC_ID: +#ifdef XML_DTD + useForeignDTD = XML_FALSE; + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; +#endif /* XML_DTD */ + dtd->hasParamEntityRefs = XML_TRUE; + if (startDoctypeDeclHandler) { + XML_Char *pubId; + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + pubId = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!pubId) + return XML_ERROR_NO_MEMORY; + normalizePublicId(pubId); + poolFinish(&tempPool); + doctypePubid = pubId; + handleDefault = XML_FALSE; + goto alreadyChecked; + } + /* fall through */ + case XML_ROLE_ENTITY_PUBLIC_ID: + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + alreadyChecked: + if (dtd->keepProcessing && declEntity) { + XML_Char *tem = poolStoreString(&dtd->pool, + enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + declEntity->publicId = tem; + poolFinish(&dtd->pool); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_DOCTYPE_CLOSE: + if (doctypeName) { + startDoctypeDeclHandler(handlerArg, doctypeName, + doctypeSysid, doctypePubid, 0); + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + /* doctypeSysid will be non-NULL in the case of a previous + XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler + was not set, indicating an external subset + */ +#ifdef XML_DTD + if (doctypeSysid || useForeignDTD) { + XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; + dtd->hasParamEntityRefs = XML_TRUE; + if (paramEntityParsing && externalEntityRefHandler) { + ENTITY *entity = (ENTITY *)lookup(parser, + &dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!entity) + return XML_ERROR_NO_MEMORY; + if (useForeignDTD) + entity->base = curBase; + dtd->paramEntityRead = XML_FALSE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (!dtd->standalone && + notStandaloneHandler && + !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + } + /* if we didn't read the foreign DTD then this means that there + is no external subset and we must reset dtd->hasParamEntityRefs + */ + else if (!doctypeSysid) + dtd->hasParamEntityRefs = hadParamEntityRefs; + /* end of DTD - no need to update dtd->keepProcessing */ + } + useForeignDTD = XML_FALSE; + } +#endif /* XML_DTD */ + if (endDoctypeDeclHandler) { + endDoctypeDeclHandler(handlerArg); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_INSTANCE_START: +#ifdef XML_DTD + /* if there is no DOCTYPE declaration then now is the + last chance to read the foreign DTD + */ + if (useForeignDTD) { + XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; + dtd->hasParamEntityRefs = XML_TRUE; + if (paramEntityParsing && externalEntityRefHandler) { + ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!entity) + return XML_ERROR_NO_MEMORY; + entity->base = curBase; + dtd->paramEntityRead = XML_FALSE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (!dtd->standalone && + notStandaloneHandler && + !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + } + /* if we didn't read the foreign DTD then this means that there + is no external subset and we must reset dtd->hasParamEntityRefs + */ + else + dtd->hasParamEntityRefs = hadParamEntityRefs; + /* end of DTD - no need to update dtd->keepProcessing */ + } + } +#endif /* XML_DTD */ + processor = contentProcessor; + return contentProcessor(parser, s, end, nextPtr); + case XML_ROLE_ATTLIST_ELEMENT_NAME: + declElementType = getElementType(parser, enc, s, next); + if (!declElementType) + return XML_ERROR_NO_MEMORY; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_NAME: + declAttributeId = getAttributeId(parser, enc, s, next); + if (!declAttributeId) + return XML_ERROR_NO_MEMORY; + declAttributeIsCdata = XML_FALSE; + declAttributeType = NULL; + declAttributeIsId = XML_FALSE; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_CDATA: + declAttributeIsCdata = XML_TRUE; + declAttributeType = atypeCDATA; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ID: + declAttributeIsId = XML_TRUE; + declAttributeType = atypeID; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_IDREF: + declAttributeType = atypeIDREF; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_IDREFS: + declAttributeType = atypeIDREFS; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ENTITY: + declAttributeType = atypeENTITY; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES: + declAttributeType = atypeENTITIES; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN: + declAttributeType = atypeNMTOKEN; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS: + declAttributeType = atypeNMTOKENS; + checkAttListDeclHandler: + if (dtd->keepProcessing && attlistDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ATTRIBUTE_ENUM_VALUE: + case XML_ROLE_ATTRIBUTE_NOTATION_VALUE: + if (dtd->keepProcessing && attlistDeclHandler) { + const XML_Char *prefix; + if (declAttributeType) { + prefix = enumValueSep; + } + else { + prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE + ? notationPrefix + : enumValueStart); + } + if (!poolAppendString(&tempPool, prefix)) + return XML_ERROR_NO_MEMORY; + if (!poolAppend(&tempPool, enc, s, next)) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE: + case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE: + if (dtd->keepProcessing) { + if (!defineAttribute(declElementType, declAttributeId, + declAttributeIsCdata, declAttributeIsId, + 0, parser)) + return XML_ERROR_NO_MEMORY; + if (attlistDeclHandler && declAttributeType) { + if (*declAttributeType == XML_T(ASCII_LPAREN) + || (*declAttributeType == XML_T(ASCII_N) + && declAttributeType[1] == XML_T(ASCII_O))) { + /* Enumerated or Notation type */ + if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN)) + || !poolAppendChar(&tempPool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + poolFinish(&tempPool); + } + *eventEndPP = s; + attlistDeclHandler(handlerArg, declElementType->name, + declAttributeId->name, declAttributeType, + 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + } + break; + case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: + case XML_ROLE_FIXED_ATTRIBUTE_VALUE: + if (dtd->keepProcessing) { + const XML_Char *attVal; + enum XML_Error result = + storeAttributeValue(parser, enc, declAttributeIsCdata, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar, + &dtd->pool); + if (result) + return result; + attVal = poolStart(&dtd->pool); + poolFinish(&dtd->pool); + /* ID attributes aren't allowed to have a default */ + if (!defineAttribute(declElementType, declAttributeId, + declAttributeIsCdata, XML_FALSE, attVal, parser)) + return XML_ERROR_NO_MEMORY; + if (attlistDeclHandler && declAttributeType) { + if (*declAttributeType == XML_T(ASCII_LPAREN) + || (*declAttributeType == XML_T(ASCII_N) + && declAttributeType[1] == XML_T(ASCII_O))) { + /* Enumerated or Notation type */ + if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN)) + || !poolAppendChar(&tempPool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + poolFinish(&tempPool); + } + *eventEndPP = s; + attlistDeclHandler(handlerArg, declElementType->name, + declAttributeId->name, declAttributeType, + attVal, + role == XML_ROLE_FIXED_ATTRIBUTE_VALUE); + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + } + break; + case XML_ROLE_ENTITY_VALUE: + if (dtd->keepProcessing) { + enum XML_Error result = storeEntityValue(parser, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (declEntity) { + declEntity->textPtr = poolStart(&dtd->entityValuePool); + declEntity->textLen = (int)(poolLength(&dtd->entityValuePool)); + poolFinish(&dtd->entityValuePool); + if (entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + declEntity->is_param, + declEntity->textPtr, + declEntity->textLen, + curBase, 0, 0, 0); + handleDefault = XML_FALSE; + } + } + else + poolDiscard(&dtd->entityValuePool); + if (result != XML_ERROR_NONE) + return result; + } + break; + case XML_ROLE_DOCTYPE_SYSTEM_ID: +#ifdef XML_DTD + useForeignDTD = XML_FALSE; +#endif /* XML_DTD */ + dtd->hasParamEntityRefs = XML_TRUE; + if (startDoctypeDeclHandler) { + doctypeSysid = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (doctypeSysid == NULL) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + handleDefault = XML_FALSE; + } +#ifdef XML_DTD + else + /* use externalSubsetName to make doctypeSysid non-NULL + for the case where no startDoctypeDeclHandler is set */ + doctypeSysid = externalSubsetName; +#endif /* XML_DTD */ + if (!dtd->standalone +#ifdef XML_DTD + && !paramEntityParsing +#endif /* XML_DTD */ + && notStandaloneHandler + && !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; +#ifndef XML_DTD + break; +#else /* XML_DTD */ + if (!declEntity) { + declEntity = (ENTITY *)lookup(parser, + &dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + declEntity->publicId = NULL; + } + /* fall through */ +#endif /* XML_DTD */ + case XML_ROLE_ENTITY_SYSTEM_ID: + if (dtd->keepProcessing && declEntity) { + declEntity->systemId = poolStoreString(&dtd->pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!declEntity->systemId) + return XML_ERROR_NO_MEMORY; + declEntity->base = curBase; + poolFinish(&dtd->pool); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_ENTITY_COMPLETE: + if (dtd->keepProcessing && declEntity && entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + declEntity->is_param, + 0,0, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + 0); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_ENTITY_NOTATION_NAME: + if (dtd->keepProcessing && declEntity) { + declEntity->notation = poolStoreString(&dtd->pool, enc, s, next); + if (!declEntity->notation) + return XML_ERROR_NO_MEMORY; + poolFinish(&dtd->pool); + if (unparsedEntityDeclHandler) { + *eventEndPP = s; + unparsedEntityDeclHandler(handlerArg, + declEntity->name, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + declEntity->notation); + handleDefault = XML_FALSE; + } + else if (entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + 0,0,0, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + declEntity->notation); + handleDefault = XML_FALSE; + } + } + break; + case XML_ROLE_GENERAL_ENTITY_NAME: + { + if (XmlPredefinedEntityName(enc, s, next)) { + declEntity = NULL; + break; + } + if (dtd->keepProcessing) { + const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { + poolDiscard(&dtd->pool); + declEntity = NULL; + } + else { + poolFinish(&dtd->pool); + declEntity->publicId = NULL; + declEntity->is_param = XML_FALSE; + /* if we have a parent parser or are reading an internal parameter + entity, then the entity declaration is not considered "internal" + */ + declEntity->is_internal = !(parentParser || openInternalEntities); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + } + else { + poolDiscard(&dtd->pool); + declEntity = NULL; + } + } + break; + case XML_ROLE_PARAM_ENTITY_NAME: +#ifdef XML_DTD + if (dtd->keepProcessing) { + const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities, + name, sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { + poolDiscard(&dtd->pool); + declEntity = NULL; + } + else { + poolFinish(&dtd->pool); + declEntity->publicId = NULL; + declEntity->is_param = XML_TRUE; + /* if we have a parent parser or are reading an internal parameter + entity, then the entity declaration is not considered "internal" + */ + declEntity->is_internal = !(parentParser || openInternalEntities); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + } + else { + poolDiscard(&dtd->pool); + declEntity = NULL; + } +#else /* not XML_DTD */ + declEntity = NULL; +#endif /* XML_DTD */ + break; + case XML_ROLE_NOTATION_NAME: + declNotationPublicId = NULL; + declNotationName = NULL; + if (notationDeclHandler) { + declNotationName = poolStoreString(&tempPool, enc, s, next); + if (!declNotationName) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_NOTATION_PUBLIC_ID: + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + if (declNotationName) { /* means notationDeclHandler != NULL */ + XML_Char *tem = poolStoreString(&tempPool, + enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + declNotationPublicId = tem; + poolFinish(&tempPool); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_NOTATION_SYSTEM_ID: + if (declNotationName && notationDeclHandler) { + const XML_Char *systemId + = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!systemId) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; + notationDeclHandler(handlerArg, + declNotationName, + curBase, + systemId, + declNotationPublicId); + handleDefault = XML_FALSE; + } + poolClear(&tempPool); + break; + case XML_ROLE_NOTATION_NO_SYSTEM_ID: + if (declNotationPublicId && notationDeclHandler) { + *eventEndPP = s; + notationDeclHandler(handlerArg, + declNotationName, + curBase, + 0, + declNotationPublicId); + handleDefault = XML_FALSE; + } + poolClear(&tempPool); + break; + case XML_ROLE_ERROR: + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: + /* PE references in internal subset are + not allowed within declarations. */ + return XML_ERROR_PARAM_ENTITY_REF; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + default: + return XML_ERROR_SYNTAX; + } +#ifdef XML_DTD + case XML_ROLE_IGNORE_SECT: + { + enum XML_Error result; + if (defaultHandler) + reportDefault(parser, enc, s, next); + handleDefault = XML_FALSE; + result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore); + if (result != XML_ERROR_NONE) + return result; + else if (!next) { + processor = ignoreSectionProcessor; + return result; + } + } + break; +#endif /* XML_DTD */ + case XML_ROLE_GROUP_OPEN: + if (prologState.level >= groupSize) { + if (groupSize) { + char *temp = (char *)REALLOC(groupConnector, groupSize *= 2); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + groupConnector = temp; + if (dtd->scaffIndex) { + int *temp = (int *)REALLOC(dtd->scaffIndex, + groupSize * sizeof(int)); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + dtd->scaffIndex = temp; + } + } + else { + groupConnector = (char *)MALLOC(groupSize = 32); + if (!groupConnector) + return XML_ERROR_NO_MEMORY; + } + } + groupConnector[prologState.level] = 0; + if (dtd->in_eldecl) { + int myindex = nextScaffoldPart(parser); + if (myindex < 0) + return XML_ERROR_NO_MEMORY; + dtd->scaffIndex[dtd->scaffLevel] = myindex; + dtd->scaffLevel++; + dtd->scaffold[myindex].type = XML_CTYPE_SEQ; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_GROUP_SEQUENCE: + if (groupConnector[prologState.level] == ASCII_PIPE) + return XML_ERROR_SYNTAX; + groupConnector[prologState.level] = ASCII_COMMA; + if (dtd->in_eldecl && elementDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_GROUP_CHOICE: + if (groupConnector[prologState.level] == ASCII_COMMA) + return XML_ERROR_SYNTAX; + if (dtd->in_eldecl + && !groupConnector[prologState.level] + && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + != XML_CTYPE_MIXED) + ) { + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + = XML_CTYPE_CHOICE; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + groupConnector[prologState.level] = ASCII_PIPE; + break; + case XML_ROLE_PARAM_ENTITY_REF: +#ifdef XML_DTD + case XML_ROLE_INNER_PARAM_ENTITY_REF: + dtd->hasParamEntityRefs = XML_TRUE; + if (!paramEntityParsing) + dtd->keepProcessing = dtd->standalone; + else { + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&dtd->pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); + poolDiscard(&dtd->pool); + /* first, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal, + otherwise call the skipped entity handler + */ + if (prologState.documentEntity && + (dtd->standalone + ? !openInternalEntities + : !dtd->hasParamEntityRefs)) { + if (!entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (!entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } + else if (!entity) { + dtd->keepProcessing = dtd->standalone; + /* cannot report skipped entities in declarations */ + if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) { + skippedEntityHandler(handlerArg, name, 1); + handleDefault = XML_FALSE; + } + break; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->textPtr) { + enum XML_Error result; + XML_Bool betweenDecl = + (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE); + result = processInternalEntity(parser, entity, betweenDecl); + if (result != XML_ERROR_NONE) + return result; + handleDefault = XML_FALSE; + break; + } + if (externalEntityRefHandler) { + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) { + entity->open = XML_FALSE; + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + } + entity->open = XML_FALSE; + handleDefault = XML_FALSE; + if (!dtd->paramEntityRead) { + dtd->keepProcessing = dtd->standalone; + break; + } + } + else { + dtd->keepProcessing = dtd->standalone; + break; + } + } +#endif /* XML_DTD */ + if (!dtd->standalone && + notStandaloneHandler && + !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + break; + + /* Element declaration stuff */ + + case XML_ROLE_ELEMENT_NAME: + if (elementDeclHandler) { + declElementType = getElementType(parser, enc, s, next); + if (!declElementType) + return XML_ERROR_NO_MEMORY; + dtd->scaffLevel = 0; + dtd->scaffCount = 0; + dtd->in_eldecl = XML_TRUE; + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_ANY: + case XML_ROLE_CONTENT_EMPTY: + if (dtd->in_eldecl) { + if (elementDeclHandler) { + XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content)); + if (!content) + return XML_ERROR_NO_MEMORY; + content->quant = XML_CQUANT_NONE; + content->name = NULL; + content->numchildren = 0; + content->children = NULL; + content->type = ((role == XML_ROLE_CONTENT_ANY) ? + XML_CTYPE_ANY : + XML_CTYPE_EMPTY); + *eventEndPP = s; + elementDeclHandler(handlerArg, declElementType->name, content); + handleDefault = XML_FALSE; + } + dtd->in_eldecl = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_PCDATA: + if (dtd->in_eldecl) { + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + = XML_CTYPE_MIXED; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_ELEMENT: + quant = XML_CQUANT_NONE; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_OPT: + quant = XML_CQUANT_OPT; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_REP: + quant = XML_CQUANT_REP; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_PLUS: + quant = XML_CQUANT_PLUS; + elementContent: + if (dtd->in_eldecl) { + ELEMENT_TYPE *el; + const XML_Char *name; + int nameLen; + const char *nxt = (quant == XML_CQUANT_NONE + ? next + : next - enc->minBytesPerChar); + int myindex = nextScaffoldPart(parser); + if (myindex < 0) + return XML_ERROR_NO_MEMORY; + dtd->scaffold[myindex].type = XML_CTYPE_NAME; + dtd->scaffold[myindex].quant = quant; + el = getElementType(parser, enc, s, nxt); + if (!el) + return XML_ERROR_NO_MEMORY; + name = el->name; + dtd->scaffold[myindex].name = name; + nameLen = 0; + for (; name[nameLen++]; ); + dtd->contentStringLen += nameLen; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_GROUP_CLOSE: + quant = XML_CQUANT_NONE; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_OPT: + quant = XML_CQUANT_OPT; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_REP: + quant = XML_CQUANT_REP; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_PLUS: + quant = XML_CQUANT_PLUS; + closeGroup: + if (dtd->in_eldecl) { + if (elementDeclHandler) + handleDefault = XML_FALSE; + dtd->scaffLevel--; + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant; + if (dtd->scaffLevel == 0) { + if (!handleDefault) { + XML_Content *model = build_model(parser); + if (!model) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; + elementDeclHandler(handlerArg, declElementType->name, model); + } + dtd->in_eldecl = XML_FALSE; + dtd->contentStringLen = 0; + } + } + break; + /* End element declaration stuff */ + + case XML_ROLE_PI: + if (!reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + handleDefault = XML_FALSE; + break; + case XML_ROLE_COMMENT: + if (!reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + handleDefault = XML_FALSE; + break; + case XML_ROLE_NONE: + switch (tok) { + case XML_TOK_BOM: + handleDefault = XML_FALSE; + break; + } + break; + case XML_ROLE_DOCTYPE_NONE: + if (startDoctypeDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ENTITY_NONE: + if (dtd->keepProcessing && entityDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_NOTATION_NONE: + if (notationDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ATTLIST_NONE: + if (dtd->keepProcessing && attlistDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ELEMENT_NONE: + if (elementDeclHandler) + handleDefault = XML_FALSE; + break; + } /* end of big switch */ + + if (handleDefault && defaultHandler) + reportDefault(parser, enc, s, next); + + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: + s = next; + tok = XmlPrologTok(enc, s, end, &next); + } + } + /* not reached */ +} + +static enum XML_Error PTRCALL +epilogProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + processor = epilogProcessor; + eventPtr = s; + for (;;) { + const char *next = NULL; + int tok = XmlPrologTok(encoding, s, end, &next); + eventEndPtr = next; + switch (tok) { + /* report partial linebreak - it might be the last token */ + case -XML_TOK_PROLOG_S: + if (defaultHandler) { + reportDefault(parser, encoding, s, next); + if (ps_parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + } + *nextPtr = next; + return XML_ERROR_NONE; + case XML_TOK_NONE: + *nextPtr = s; + return XML_ERROR_NONE; + case XML_TOK_PROLOG_S: + if (defaultHandler) + reportDefault(parser, encoding, s, next); + break; + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_INVALID: + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (!ps_finalBuffer) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (!ps_finalBuffer) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + default: + return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; + } + eventPtr = s = next; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: ; + } + } +} + +static enum XML_Error +processInternalEntity(XML_Parser parser, ENTITY *entity, + XML_Bool betweenDecl) +{ + const char *textStart, *textEnd; + const char *next; + enum XML_Error result; + OPEN_INTERNAL_ENTITY *openEntity; + + if (freeInternalEntities) { + openEntity = freeInternalEntities; + freeInternalEntities = openEntity->next; + } + else { + openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY)); + if (!openEntity) + return XML_ERROR_NO_MEMORY; + } + entity->open = XML_TRUE; + entity->processed = 0; + openEntity->next = openInternalEntities; + openInternalEntities = openEntity; + openEntity->entity = entity; + openEntity->startTagLevel = tagLevel; + openEntity->betweenDecl = betweenDecl; + openEntity->internalEventPtr = NULL; + openEntity->internalEventEndPtr = NULL; + textStart = (char *)entity->textPtr; + textEnd = (char *)(entity->textPtr + entity->textLen); + +#ifdef XML_DTD + if (entity->is_param) { + int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); + result = doProlog(parser, internalEncoding, textStart, textEnd, tok, + next, &next, XML_FALSE); + } + else +#endif /* XML_DTD */ + result = doContent(parser, tagLevel, internalEncoding, textStart, + textEnd, &next, XML_FALSE); + + if (result == XML_ERROR_NONE) { + if (textEnd != next && ps_parsing == XML_SUSPENDED) { + entity->processed = (int)(next - textStart); + processor = internalEntityProcessor; + } + else { + entity->open = XML_FALSE; + openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = freeInternalEntities; + freeInternalEntities = openEntity; + } + } + return result; +} + +static enum XML_Error PTRCALL +internalEntityProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + ENTITY *entity; + const char *textStart, *textEnd; + const char *next; + enum XML_Error result; + OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities; + if (!openEntity) + return XML_ERROR_UNEXPECTED_STATE; + + entity = openEntity->entity; + textStart = ((char *)entity->textPtr) + entity->processed; + textEnd = (char *)(entity->textPtr + entity->textLen); + +#ifdef XML_DTD + if (entity->is_param) { + int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); + result = doProlog(parser, internalEncoding, textStart, textEnd, tok, + next, &next, XML_FALSE); + } + else +#endif /* XML_DTD */ + result = doContent(parser, openEntity->startTagLevel, internalEncoding, + textStart, textEnd, &next, XML_FALSE); + + if (result != XML_ERROR_NONE) + return result; + else if (textEnd != next && ps_parsing == XML_SUSPENDED) { + entity->processed = (int)(next - (char *)entity->textPtr); + return result; + } + else { + entity->open = XML_FALSE; + openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = freeInternalEntities; + freeInternalEntities = openEntity; + } + +#ifdef XML_DTD + if (entity->is_param) { + int tok; + processor = prologProcessor; + tok = XmlPrologTok(encoding, s, end, &next); + return doProlog(parser, encoding, s, end, tok, next, nextPtr, + (XML_Bool)!ps_finalBuffer); + } + else +#endif /* XML_DTD */ + { + processor = contentProcessor; + /* see externalEntityContentProcessor vs contentProcessor */ + return doContent(parser, parentParser ? 1 : 0, encoding, s, end, + nextPtr, (XML_Bool)!ps_finalBuffer); + } +} + +static enum XML_Error PTRCALL +errorProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + return errorCode; +} + +static enum XML_Error +storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, + const char *ptr, const char *end, + STRING_POOL *pool) +{ + enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, + end, pool); + if (result) + return result; + if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20) + poolChop(pool); + if (!poolAppendChar(pool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + return XML_ERROR_NONE; +} + +static enum XML_Error +appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, + const char *ptr, const char *end, + STRING_POOL *pool) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + for (;;) { + const char *next; + int tok = XmlAttributeValueTok(enc, ptr, end, &next); + switch (tok) { + case XML_TOK_NONE: + return XML_ERROR_NONE; + case XML_TOK_INVALID: + if (enc == encoding) + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, ptr); + if (n < 0) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + } + if (!isCdata + && n == 0x20 /* space */ + && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + n = XmlEncode(n, (ICHAR *)buf); + if (!n) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + } + for (i = 0; i < n; i++) { + if (!poolAppendChar(pool, buf[i])) + return XML_ERROR_NO_MEMORY; + } + } + break; + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, enc, ptr, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_TRAILING_CR: + next = ptr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_ATTRIBUTE_VALUE_S: + case XML_TOK_DATA_NEWLINE: + if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + if (!poolAppendChar(pool, 0x20)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + char checkEntityDecl; + XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (ch) { + if (!poolAppendChar(pool, ch)) + return XML_ERROR_NO_MEMORY; + break; + } + name = poolStoreString(&temp2Pool, enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); + poolDiscard(&temp2Pool); + /* First, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal. + */ + if (pool == &dtd->pool) /* are we called from prolog? */ + checkEntityDecl = +#ifdef XML_DTD + prologState.documentEntity && +#endif /* XML_DTD */ + (dtd->standalone + ? !openInternalEntities + : !dtd->hasParamEntityRefs); + else /* if (pool == &tempPool): we are called from content */ + checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone; + if (checkEntityDecl) { + if (!entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (!entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } + else if (!entity) { + /* Cannot report skipped entity here - see comments on + skippedEntityHandler. + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, name, 0); + */ + /* Cannot call the default handler because this would be + out of sync with the call to the startElementHandler. + if ((pool == &tempPool) && defaultHandler) + reportDefault(parser, enc, ptr, next); + */ + break; + } + if (entity->open) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_RECURSIVE_ENTITY_REF; + } + if (entity->notation) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BINARY_ENTITY_REF; + } + if (!entity->textPtr) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; + } + else { + enum XML_Error result; + const XML_Char *textEnd = entity->textPtr + entity->textLen; + entity->open = XML_TRUE; + result = appendAttributeValue(parser, internalEncoding, isCdata, + (char *)entity->textPtr, + (char *)textEnd, pool); + entity->open = XML_FALSE; + if (result) + return result; + } + } + break; + default: + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_UNEXPECTED_STATE; + } + ptr = next; + } + /* not reached */ +} + +static enum XML_Error +storeEntityValue(XML_Parser parser, + const ENCODING *enc, + const char *entityTextPtr, + const char *entityTextEnd) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + STRING_POOL *pool = &(dtd->entityValuePool); + enum XML_Error result = XML_ERROR_NONE; +#ifdef XML_DTD + int oldInEntityValue = prologState.inEntityValue; + prologState.inEntityValue = 1; +#endif /* XML_DTD */ + /* never return Null for the value argument in EntityDeclHandler, + since this would indicate an external entity; therefore we + have to make sure that entityValuePool.start is not null */ + if (!pool->blocks) { + if (!poolGrow(pool)) + return XML_ERROR_NO_MEMORY; + } + + for (;;) { + const char *next; + int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next); + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: +#ifdef XML_DTD + if (isParamEntity || enc != encoding) { + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&tempPool, enc, + entityTextPtr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); + poolDiscard(&tempPool); + if (!entity) { + /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ + /* cannot report skipped entity here - see comments on + skippedEntityHandler + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, name, 0); + */ + dtd->keepProcessing = dtd->standalone; + goto endEntityValue; + } + if (entity->open) { + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_RECURSIVE_ENTITY_REF; + goto endEntityValue; + } + if (entity->systemId) { + if (externalEntityRefHandler) { + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) { + entity->open = XML_FALSE; + result = XML_ERROR_EXTERNAL_ENTITY_HANDLING; + goto endEntityValue; + } + entity->open = XML_FALSE; + if (!dtd->paramEntityRead) + dtd->keepProcessing = dtd->standalone; + } + else + dtd->keepProcessing = dtd->standalone; + } + else { + entity->open = XML_TRUE; + result = storeEntityValue(parser, + internalEncoding, + (char *)entity->textPtr, + (char *)(entity->textPtr + + entity->textLen)); + entity->open = XML_FALSE; + if (result) + goto endEntityValue; + } + break; + } +#endif /* XML_DTD */ + /* In the internal subset, PE references are not legal + within markup declarations, e.g entity values in this case. */ + eventPtr = entityTextPtr; + result = XML_ERROR_PARAM_ENTITY_REF; + goto endEntityValue; + case XML_TOK_NONE: + result = XML_ERROR_NONE; + goto endEntityValue; + case XML_TOK_ENTITY_REF: + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, enc, entityTextPtr, next)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + break; + case XML_TOK_TRAILING_CR: + next = entityTextPtr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_DATA_NEWLINE: + if (pool->end == pool->ptr && !poolGrow(pool)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + *(pool->ptr)++ = 0xA; + break; + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, entityTextPtr); + if (n < 0) { + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_BAD_CHAR_REF; + goto endEntityValue; + } + n = XmlEncode(n, (ICHAR *)buf); + if (!n) { + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_BAD_CHAR_REF; + goto endEntityValue; + } + for (i = 0; i < n; i++) { + if (pool->end == pool->ptr && !poolGrow(pool)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + *(pool->ptr)++ = buf[i]; + } + } + break; + case XML_TOK_PARTIAL: + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_INVALID_TOKEN; + goto endEntityValue; + case XML_TOK_INVALID: + if (enc == encoding) + eventPtr = next; + result = XML_ERROR_INVALID_TOKEN; + goto endEntityValue; + default: + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_UNEXPECTED_STATE; + goto endEntityValue; + } + entityTextPtr = next; + } +endEntityValue: +#ifdef XML_DTD + prologState.inEntityValue = oldInEntityValue; +#endif /* XML_DTD */ + return result; +} + +static void FASTCALL +normalizeLines(XML_Char *s) +{ + XML_Char *p; + for (;; s++) { + if (*s == XML_T('\0')) + return; + if (*s == 0xD) + break; + } + p = s; + do { + if (*s == 0xD) { + *p++ = 0xA; + if (*++s == 0xA) + s++; + } + else + *p++ = *s++; + } while (*s); + *p = XML_T('\0'); +} + +static int +reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end) +{ + const XML_Char *target; + XML_Char *data; + const char *tem; + if (!processingInstructionHandler) { + if (defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + start += enc->minBytesPerChar * 2; + tem = start + XmlNameLength(enc, start); + target = poolStoreString(&tempPool, enc, start, tem); + if (!target) + return 0; + poolFinish(&tempPool); + data = poolStoreString(&tempPool, enc, + XmlSkipS(enc, tem), + end - enc->minBytesPerChar*2); + if (!data) + return 0; + normalizeLines(data); + processingInstructionHandler(handlerArg, target, data); + poolClear(&tempPool); + return 1; +} + +static int +reportComment(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end) +{ + XML_Char *data; + if (!commentHandler) { + if (defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + data = poolStoreString(&tempPool, + enc, + start + enc->minBytesPerChar * 4, + end - enc->minBytesPerChar * 3); + if (!data) + return 0; + normalizeLines(data); + commentHandler(handlerArg, data); + poolClear(&tempPool); + return 1; +} + +static void +reportDefault(XML_Parser parser, const ENCODING *enc, + const char *s, const char *end) +{ + if (MUST_CONVERT(enc, s)) { + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + do { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = s; + defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf)); + *eventPP = s; + } while (s != end); + } + else + defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s)); +} + + +static int +defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, + XML_Bool isId, const XML_Char *value, XML_Parser parser) +{ + DEFAULT_ATTRIBUTE *att; + if (value || isId) { + /* The handling of default attributes gets messed up if we have + a default which duplicates a non-default. */ + int i; + for (i = 0; i < type->nDefaultAtts; i++) + if (attId == type->defaultAtts[i].id) + return 1; + if (isId && !type->idAtt && !attId->xmlns) + type->idAtt = attId; + } + if (type->nDefaultAtts == type->allocDefaultAtts) { + if (type->allocDefaultAtts == 0) { + type->allocDefaultAtts = 8; + type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts + * sizeof(DEFAULT_ATTRIBUTE)); + if (!type->defaultAtts) + return 0; + } + else { + DEFAULT_ATTRIBUTE *temp; + int count = type->allocDefaultAtts * 2; + temp = (DEFAULT_ATTRIBUTE *) + REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE))); + if (temp == NULL) + return 0; + type->allocDefaultAtts = count; + type->defaultAtts = temp; + } + } + att = type->defaultAtts + type->nDefaultAtts; + att->id = attId; + att->value = value; + att->isCdata = isCdata; + if (!isCdata) + attId->maybeTokenized = XML_TRUE; + type->nDefaultAtts += 1; + return 1; +} + +static int +setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + const XML_Char *name; + for (name = elementType->name; *name; name++) { + if (*name == XML_T(ASCII_COLON)) { + PREFIX *prefix; + const XML_Char *s; + for (s = elementType->name; s != name; s++) { + if (!poolAppendChar(&dtd->pool, *s)) + return 0; + } + if (!poolAppendChar(&dtd->pool, XML_T('\0'))) + return 0; + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), + sizeof(PREFIX)); + if (!prefix) + return 0; + if (prefix->name == poolStart(&dtd->pool)) + poolFinish(&dtd->pool); + else + poolDiscard(&dtd->pool); + elementType->prefix = prefix; + + } + } + return 1; +} + +static ATTRIBUTE_ID * +getAttributeId(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + ATTRIBUTE_ID *id; + const XML_Char *name; + if (!poolAppendChar(&dtd->pool, XML_T('\0'))) + return NULL; + name = poolStoreString(&dtd->pool, enc, start, end); + if (!name) + return NULL; + /* skip quotation mark - its storage will be re-used (like in name[-1]) */ + ++name; + id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); + if (!id) + return NULL; + if (id->name != name) + poolDiscard(&dtd->pool); + else { + poolFinish(&dtd->pool); + if (!ns) + ; + else if (name[0] == XML_T(ASCII_x) + && name[1] == XML_T(ASCII_m) + && name[2] == XML_T(ASCII_l) + && name[3] == XML_T(ASCII_n) + && name[4] == XML_T(ASCII_s) + && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) { + if (name[5] == XML_T('\0')) + id->prefix = &dtd->defaultPrefix; + else + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX)); + id->xmlns = XML_TRUE; + } + else { + int i; + for (i = 0; name[i]; i++) { + /* attributes without prefix are *not* in the default namespace */ + if (name[i] == XML_T(ASCII_COLON)) { + int j; + for (j = 0; j < i; j++) { + if (!poolAppendChar(&dtd->pool, name[j])) + return NULL; + } + if (!poolAppendChar(&dtd->pool, XML_T('\0'))) + return NULL; + id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), + sizeof(PREFIX)); + if (id->prefix->name == poolStart(&dtd->pool)) + poolFinish(&dtd->pool); + else + poolDiscard(&dtd->pool); + break; + } + } + } + } + return id; +} + +#define CONTEXT_SEP XML_T(ASCII_FF) + +static const XML_Char * +getContext(XML_Parser parser) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + HASH_TABLE_ITER iter; + XML_Bool needSep = XML_FALSE; + + if (dtd->defaultPrefix.binding) { + int i; + int len; + if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS))) + return NULL; + len = dtd->defaultPrefix.binding->uriLen; + if (namespaceSeparator) + len--; + for (i = 0; i < len; i++) + if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i])) + return NULL; + needSep = XML_TRUE; + } + + hashTableIterInit(&iter, &(dtd->prefixes)); + for (;;) { + int i; + int len; + const XML_Char *s; + PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter); + if (!prefix) + break; + if (!prefix->binding) + continue; + if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) + return NULL; + for (s = prefix->name; *s; s++) + if (!poolAppendChar(&tempPool, *s)) + return NULL; + if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS))) + return NULL; + len = prefix->binding->uriLen; + if (namespaceSeparator) + len--; + for (i = 0; i < len; i++) + if (!poolAppendChar(&tempPool, prefix->binding->uri[i])) + return NULL; + needSep = XML_TRUE; + } + + + hashTableIterInit(&iter, &(dtd->generalEntities)); + for (;;) { + const XML_Char *s; + ENTITY *e = (ENTITY *)hashTableIterNext(&iter); + if (!e) + break; + if (!e->open) + continue; + if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) + return NULL; + for (s = e->name; *s; s++) + if (!poolAppendChar(&tempPool, *s)) + return 0; + needSep = XML_TRUE; + } + + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return NULL; + return tempPool.start; +} + +static XML_Bool +setContext(XML_Parser parser, const XML_Char *context) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + const XML_Char *s = context; + + while (*context != XML_T('\0')) { + if (*s == CONTEXT_SEP || *s == XML_T('\0')) { + ENTITY *e; + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return XML_FALSE; + e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0); + if (e) + e->open = XML_TRUE; + if (*s != XML_T('\0')) + s++; + context = s; + poolDiscard(&tempPool); + } + else if (*s == XML_T(ASCII_EQUALS)) { + PREFIX *prefix; + if (poolLength(&tempPool) == 0) + prefix = &dtd->defaultPrefix; + else { + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return XML_FALSE; + prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool), + sizeof(PREFIX)); + if (!prefix) + return XML_FALSE; + if (prefix->name == poolStart(&tempPool)) { + prefix->name = poolCopyString(&dtd->pool, prefix->name); + if (!prefix->name) + return XML_FALSE; + } + poolDiscard(&tempPool); + } + for (context = s + 1; + *context != CONTEXT_SEP && *context != XML_T('\0'); + context++) + if (!poolAppendChar(&tempPool, *context)) + return XML_FALSE; + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return XML_FALSE; + if (addBinding(parser, prefix, NULL, poolStart(&tempPool), + &inheritedBindings) != XML_ERROR_NONE) + return XML_FALSE; + poolDiscard(&tempPool); + if (*context != XML_T('\0')) + ++context; + s = context; + } + else { + if (!poolAppendChar(&tempPool, *s)) + return XML_FALSE; + s++; + } + } + return XML_TRUE; +} + +static void FASTCALL +normalizePublicId(XML_Char *publicId) +{ + XML_Char *p = publicId; + XML_Char *s; + for (s = publicId; *s; s++) { + switch (*s) { + case 0x20: + case 0xD: + case 0xA: + if (p != publicId && p[-1] != 0x20) + *p++ = 0x20; + break; + default: + *p++ = *s; + } + } + if (p != publicId && p[-1] == 0x20) + --p; + *p = XML_T('\0'); +} + +static DTD * +dtdCreate(const XML_Memory_Handling_Suite *ms) +{ + DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD)); + if (p == NULL) + return p; + poolInit(&(p->pool), ms); + poolInit(&(p->entityValuePool), ms); + hashTableInit(&(p->generalEntities), ms); + hashTableInit(&(p->elementTypes), ms); + hashTableInit(&(p->attributeIds), ms); + hashTableInit(&(p->prefixes), ms); +#ifdef XML_DTD + p->paramEntityRead = XML_FALSE; + hashTableInit(&(p->paramEntities), ms); +#endif /* XML_DTD */ + p->defaultPrefix.name = NULL; + p->defaultPrefix.binding = NULL; + + p->in_eldecl = XML_FALSE; + p->scaffIndex = NULL; + p->scaffold = NULL; + p->scaffLevel = 0; + p->scaffSize = 0; + p->scaffCount = 0; + p->contentStringLen = 0; + + p->keepProcessing = XML_TRUE; + p->hasParamEntityRefs = XML_FALSE; + p->standalone = XML_FALSE; + return p; +} + +static void +dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) +{ + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &(p->elementTypes)); + for (;;) { + ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!e) + break; + if (e->allocDefaultAtts != 0) + ms->free_fcn(e->defaultAtts); + } + hashTableClear(&(p->generalEntities)); +#ifdef XML_DTD + p->paramEntityRead = XML_FALSE; + hashTableClear(&(p->paramEntities)); +#endif /* XML_DTD */ + hashTableClear(&(p->elementTypes)); + hashTableClear(&(p->attributeIds)); + hashTableClear(&(p->prefixes)); + poolClear(&(p->pool)); + poolClear(&(p->entityValuePool)); + p->defaultPrefix.name = NULL; + p->defaultPrefix.binding = NULL; + + p->in_eldecl = XML_FALSE; + + ms->free_fcn(p->scaffIndex); + p->scaffIndex = NULL; + ms->free_fcn(p->scaffold); + p->scaffold = NULL; + + p->scaffLevel = 0; + p->scaffSize = 0; + p->scaffCount = 0; + p->contentStringLen = 0; + + p->keepProcessing = XML_TRUE; + p->hasParamEntityRefs = XML_FALSE; + p->standalone = XML_FALSE; +} + +static void +dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) +{ + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &(p->elementTypes)); + for (;;) { + ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!e) + break; + if (e->allocDefaultAtts != 0) + ms->free_fcn(e->defaultAtts); + } + hashTableDestroy(&(p->generalEntities)); +#ifdef XML_DTD + hashTableDestroy(&(p->paramEntities)); +#endif /* XML_DTD */ + hashTableDestroy(&(p->elementTypes)); + hashTableDestroy(&(p->attributeIds)); + hashTableDestroy(&(p->prefixes)); + poolDestroy(&(p->pool)); + poolDestroy(&(p->entityValuePool)); + if (isDocEntity) { + ms->free_fcn(p->scaffIndex); + ms->free_fcn(p->scaffold); + } + ms->free_fcn(p); +} + +/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise. + The new DTD has already been initialized. +*/ +static int +dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) +{ + HASH_TABLE_ITER iter; + + /* Copy the prefix table. */ + + hashTableIterInit(&iter, &(oldDtd->prefixes)); + for (;;) { + const XML_Char *name; + const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter); + if (!oldP) + break; + name = poolCopyString(&(newDtd->pool), oldP->name); + if (!name) + return 0; + if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) + return 0; + } + + hashTableIterInit(&iter, &(oldDtd->attributeIds)); + + /* Copy the attribute id table. */ + + for (;;) { + ATTRIBUTE_ID *newA; + const XML_Char *name; + const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter); + + if (!oldA) + break; + /* Remember to allocate the scratch byte before the name. */ + if (!poolAppendChar(&(newDtd->pool), XML_T('\0'))) + return 0; + name = poolCopyString(&(newDtd->pool), oldA->name); + if (!name) + return 0; + ++name; + newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name, + sizeof(ATTRIBUTE_ID)); + if (!newA) + return 0; + newA->maybeTokenized = oldA->maybeTokenized; + if (oldA->prefix) { + newA->xmlns = oldA->xmlns; + if (oldA->prefix == &oldDtd->defaultPrefix) + newA->prefix = &newDtd->defaultPrefix; + else + newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), + oldA->prefix->name, 0); + } + } + + /* Copy the element type table. */ + + hashTableIterInit(&iter, &(oldDtd->elementTypes)); + + for (;;) { + int i; + ELEMENT_TYPE *newE; + const XML_Char *name; + const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!oldE) + break; + name = poolCopyString(&(newDtd->pool), oldE->name); + if (!name) + return 0; + newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name, + sizeof(ELEMENT_TYPE)); + if (!newE) + return 0; + if (oldE->nDefaultAtts) { + newE->defaultAtts = (DEFAULT_ATTRIBUTE *) + ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); + if (!newE->defaultAtts) { + ms->free_fcn(newE); + return 0; + } + } + if (oldE->idAtt) + newE->idAtt = (ATTRIBUTE_ID *) + lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); + newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; + if (oldE->prefix) + newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), + oldE->prefix->name, 0); + for (i = 0; i < newE->nDefaultAtts; i++) { + newE->defaultAtts[i].id = (ATTRIBUTE_ID *) + lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; + if (oldE->defaultAtts[i].value) { + newE->defaultAtts[i].value + = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value); + if (!newE->defaultAtts[i].value) + return 0; + } + else + newE->defaultAtts[i].value = NULL; + } + } + + /* Copy the entity tables. */ + if (!copyEntityTable(oldParser, + &(newDtd->generalEntities), + &(newDtd->pool), + &(oldDtd->generalEntities))) + return 0; + +#ifdef XML_DTD + if (!copyEntityTable(oldParser, + &(newDtd->paramEntities), + &(newDtd->pool), + &(oldDtd->paramEntities))) + return 0; + newDtd->paramEntityRead = oldDtd->paramEntityRead; +#endif /* XML_DTD */ + + newDtd->keepProcessing = oldDtd->keepProcessing; + newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs; + newDtd->standalone = oldDtd->standalone; + + /* Don't want deep copying for scaffolding */ + newDtd->in_eldecl = oldDtd->in_eldecl; + newDtd->scaffold = oldDtd->scaffold; + newDtd->contentStringLen = oldDtd->contentStringLen; + newDtd->scaffSize = oldDtd->scaffSize; + newDtd->scaffLevel = oldDtd->scaffLevel; + newDtd->scaffIndex = oldDtd->scaffIndex; + + return 1; +} /* End dtdCopy */ + +static int +copyEntityTable(XML_Parser oldParser, + HASH_TABLE *newTable, + STRING_POOL *newPool, + const HASH_TABLE *oldTable) +{ + HASH_TABLE_ITER iter; + const XML_Char *cachedOldBase = NULL; + const XML_Char *cachedNewBase = NULL; + + hashTableIterInit(&iter, oldTable); + + for (;;) { + ENTITY *newE; + const XML_Char *name; + const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter); + if (!oldE) + break; + name = poolCopyString(newPool, oldE->name); + if (!name) + return 0; + newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); + if (!newE) + return 0; + if (oldE->systemId) { + const XML_Char *tem = poolCopyString(newPool, oldE->systemId); + if (!tem) + return 0; + newE->systemId = tem; + if (oldE->base) { + if (oldE->base == cachedOldBase) + newE->base = cachedNewBase; + else { + cachedOldBase = oldE->base; + tem = poolCopyString(newPool, cachedOldBase); + if (!tem) + return 0; + cachedNewBase = newE->base = tem; + } + } + if (oldE->publicId) { + tem = poolCopyString(newPool, oldE->publicId); + if (!tem) + return 0; + newE->publicId = tem; + } + } + else { + const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr, + oldE->textLen); + if (!tem) + return 0; + newE->textPtr = tem; + newE->textLen = oldE->textLen; + } + if (oldE->notation) { + const XML_Char *tem = poolCopyString(newPool, oldE->notation); + if (!tem) + return 0; + newE->notation = tem; + } + newE->is_param = oldE->is_param; + newE->is_internal = oldE->is_internal; + } + return 1; +} + +#define INIT_POWER 6 + +static XML_Bool FASTCALL +keyeq(KEY s1, KEY s2) +{ + for (; *s1 == *s2; s1++, s2++) + if (*s1 == 0) + return XML_TRUE; + return XML_FALSE; +} + +static unsigned long FASTCALL +hash(XML_Parser parser, KEY s) +{ + unsigned long h = hash_secret_salt; + while (*s) + h = CHAR_HASH(h, *s++); + return h; +} + +static NAMED * +lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) +{ + size_t i; + if (table->size == 0) { + size_t tsize; + if (!createSize) + return NULL; + table->power = INIT_POWER; + /* table->size is a power of 2 */ + table->size = (size_t)1 << INIT_POWER; + tsize = table->size * sizeof(NAMED *); + table->v = (NAMED **)table->mem->malloc_fcn(tsize); + if (!table->v) { + table->size = 0; + return NULL; + } + memset(table->v, 0, tsize); + i = hash(parser, name) & ((unsigned long)table->size - 1); + } + else { + unsigned long h = hash(parser, name); + unsigned long mask = (unsigned long)table->size - 1; + unsigned char step = 0; + i = h & mask; + while (table->v[i]) { + if (keyeq(name, table->v[i]->name)) + return table->v[i]; + if (!step) + step = PROBE_STEP(h, mask, table->power); + i < step ? (i += table->size - step) : (i -= step); + } + if (!createSize) + return NULL; + + /* check for overflow (table is half full) */ + if (table->used >> (table->power - 1)) { + unsigned char newPower = table->power + 1; + size_t newSize = (size_t)1 << newPower; + unsigned long newMask = (unsigned long)newSize - 1; + size_t tsize = newSize * sizeof(NAMED *); + NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize); + if (!newV) + return NULL; + memset(newV, 0, tsize); + for (i = 0; i < table->size; i++) + if (table->v[i]) { + unsigned long newHash = hash(parser, table->v[i]->name); + size_t j = newHash & newMask; + step = 0; + while (newV[j]) { + if (!step) + step = PROBE_STEP(newHash, newMask, newPower); + j < step ? (j += newSize - step) : (j -= step); + } + newV[j] = table->v[i]; + } + table->mem->free_fcn(table->v); + table->v = newV; + table->power = newPower; + table->size = newSize; + i = h & newMask; + step = 0; + while (table->v[i]) { + if (!step) + step = PROBE_STEP(h, newMask, newPower); + i < step ? (i += newSize - step) : (i -= step); + } + } + } + table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize); + if (!table->v[i]) + return NULL; + memset(table->v[i], 0, createSize); + table->v[i]->name = name; + (table->used)++; + return table->v[i]; +} + +static void FASTCALL +hashTableClear(HASH_TABLE *table) +{ + size_t i; + for (i = 0; i < table->size; i++) { + table->mem->free_fcn(table->v[i]); + table->v[i] = NULL; + } + table->used = 0; +} + +static void FASTCALL +hashTableDestroy(HASH_TABLE *table) +{ + size_t i; + for (i = 0; i < table->size; i++) + table->mem->free_fcn(table->v[i]); + table->mem->free_fcn(table->v); +} + +static void FASTCALL +hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) +{ + p->power = 0; + p->size = 0; + p->used = 0; + p->v = NULL; + p->mem = ms; +} + +static void FASTCALL +hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) +{ + iter->p = table->v; + iter->end = iter->p + table->size; +} + +static NAMED * FASTCALL +hashTableIterNext(HASH_TABLE_ITER *iter) +{ + while (iter->p != iter->end) { + NAMED *tem = *(iter->p)++; + if (tem) + return tem; + } + return NULL; +} + +static void FASTCALL +poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms) +{ + pool->blocks = NULL; + pool->freeBlocks = NULL; + pool->start = NULL; + pool->ptr = NULL; + pool->end = NULL; + pool->mem = ms; +} + +static void FASTCALL +poolClear(STRING_POOL *pool) +{ + if (!pool->freeBlocks) + pool->freeBlocks = pool->blocks; + else { + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + p->next = pool->freeBlocks; + pool->freeBlocks = p; + p = tem; + } + } + pool->blocks = NULL; + pool->start = NULL; + pool->ptr = NULL; + pool->end = NULL; +} + +static void FASTCALL +poolDestroy(STRING_POOL *pool) +{ + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + pool->mem->free_fcn(p); + p = tem; + } + p = pool->freeBlocks; + while (p) { + BLOCK *tem = p->next; + pool->mem->free_fcn(p); + p = tem; + } +} + +static XML_Char * +poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + if (!pool->ptr && !poolGrow(pool)) + return NULL; + for (;;) { + XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end); + if (ptr == end) + break; + if (!poolGrow(pool)) + return NULL; + } + return pool->start; +} + +static const XML_Char * FASTCALL +poolCopyString(STRING_POOL *pool, const XML_Char *s) +{ + do { + if (!poolAppendChar(pool, *s)) + return NULL; + } while (*s++); + s = pool->start; + poolFinish(pool); + return s; +} + +static const XML_Char * +poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) +{ + if (!pool->ptr && !poolGrow(pool)) + return NULL; + for (; n > 0; --n, s++) { + if (!poolAppendChar(pool, *s)) + return NULL; + } + s = pool->start; + poolFinish(pool); + return s; +} + +static const XML_Char * FASTCALL +poolAppendString(STRING_POOL *pool, const XML_Char *s) +{ + while (*s) { + if (!poolAppendChar(pool, *s)) + return NULL; + s++; + } + return pool->start; +} + +static XML_Char * +poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + if (!poolAppend(pool, enc, ptr, end)) + return NULL; + if (pool->ptr == pool->end && !poolGrow(pool)) + return NULL; + *(pool->ptr)++ = 0; + return pool->start; +} + +static XML_Bool FASTCALL +poolGrow(STRING_POOL *pool) +{ + if (pool->freeBlocks) { + if (pool->start == 0) { + pool->blocks = pool->freeBlocks; + pool->freeBlocks = pool->freeBlocks->next; + pool->blocks->next = NULL; + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + pool->ptr = pool->start; + return XML_TRUE; + } + if (pool->end - pool->start < pool->freeBlocks->size) { + BLOCK *tem = pool->freeBlocks->next; + pool->freeBlocks->next = pool->blocks; + pool->blocks = pool->freeBlocks; + pool->freeBlocks = tem; + memcpy(pool->blocks->s, pool->start, + (pool->end - pool->start) * sizeof(XML_Char)); + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + return XML_TRUE; + } + } + if (pool->blocks && pool->start == pool->blocks->s) { + int blockSize = (int)(pool->end - pool->start)*2; + BLOCK *temp = (BLOCK *) + pool->mem->realloc_fcn(pool->blocks, + (offsetof(BLOCK, s) + + blockSize * sizeof(XML_Char))); + if (temp == NULL) + return XML_FALSE; + pool->blocks = temp; + pool->blocks->size = blockSize; + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + blockSize; + } + else { + BLOCK *tem; + int blockSize = (int)(pool->end - pool->start); + if (blockSize < INIT_BLOCK_SIZE) + blockSize = INIT_BLOCK_SIZE; + else + blockSize *= 2; + tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s) + + blockSize * sizeof(XML_Char)); + if (!tem) + return XML_FALSE; + tem->size = blockSize; + tem->next = pool->blocks; + pool->blocks = tem; + if (pool->ptr != pool->start) + memcpy(tem->s, pool->start, + (pool->ptr - pool->start) * sizeof(XML_Char)); + pool->ptr = tem->s + (pool->ptr - pool->start); + pool->start = tem->s; + pool->end = tem->s + blockSize; + } + return XML_TRUE; +} + +static int FASTCALL +nextScaffoldPart(XML_Parser parser) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + CONTENT_SCAFFOLD * me; + int next; + + if (!dtd->scaffIndex) { + dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int)); + if (!dtd->scaffIndex) + return -1; + dtd->scaffIndex[0] = 0; + } + + if (dtd->scaffCount >= dtd->scaffSize) { + CONTENT_SCAFFOLD *temp; + if (dtd->scaffold) { + temp = (CONTENT_SCAFFOLD *) + REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); + if (temp == NULL) + return -1; + dtd->scaffSize *= 2; + } + else { + temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS + * sizeof(CONTENT_SCAFFOLD)); + if (temp == NULL) + return -1; + dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS; + } + dtd->scaffold = temp; + } + next = dtd->scaffCount++; + me = &dtd->scaffold[next]; + if (dtd->scaffLevel) { + CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]]; + if (parent->lastchild) { + dtd->scaffold[parent->lastchild].nextsib = next; + } + if (!parent->childcnt) + parent->firstchild = next; + parent->lastchild = next; + parent->childcnt++; + } + me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0; + return next; +} + +static void +build_node(XML_Parser parser, + int src_node, + XML_Content *dest, + XML_Content **contpos, + XML_Char **strpos) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + dest->type = dtd->scaffold[src_node].type; + dest->quant = dtd->scaffold[src_node].quant; + if (dest->type == XML_CTYPE_NAME) { + const XML_Char *src; + dest->name = *strpos; + src = dtd->scaffold[src_node].name; + for (;;) { + *(*strpos)++ = *src; + if (!*src) + break; + src++; + } + dest->numchildren = 0; + dest->children = NULL; + } + else { + unsigned int i; + int cn; + dest->numchildren = dtd->scaffold[src_node].childcnt; + dest->children = *contpos; + *contpos += dest->numchildren; + for (i = 0, cn = dtd->scaffold[src_node].firstchild; + i < dest->numchildren; + i++, cn = dtd->scaffold[cn].nextsib) { + build_node(parser, cn, &(dest->children[i]), contpos, strpos); + } + dest->name = NULL; + } +} + +static XML_Content * +build_model (XML_Parser parser) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + XML_Content *ret; + XML_Content *cpos; + XML_Char * str; + int allocsize = (dtd->scaffCount * sizeof(XML_Content) + + (dtd->contentStringLen * sizeof(XML_Char))); + + ret = (XML_Content *)MALLOC(allocsize); + if (!ret) + return NULL; + + str = (XML_Char *) (&ret[dtd->scaffCount]); + cpos = &ret[1]; + + build_node(parser, 0, ret, &cpos, &str); + return ret; +} + +static ELEMENT_TYPE * +getElementType(XML_Parser parser, + const ENCODING *enc, + const char *ptr, + const char *end) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end); + ELEMENT_TYPE *ret; + + if (!name) + return NULL; + ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); + if (!ret) + return NULL; + if (ret->name != name) + poolDiscard(&dtd->pool); + else { + poolFinish(&dtd->pool); + if (!setElementTypePrefix(parser, ret)) + return NULL; + } + return ret; +} diff -Nru simgear-2.10.0/3rdparty/expat/xmlparse.h simgear-3.0.0/3rdparty/expat/xmlparse.h --- simgear-2.10.0/3rdparty/expat/xmlparse.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/xmlparse.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,482 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (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.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + +#ifndef XmlParse_INCLUDED +#define XmlParse_INCLUDED 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef XMLPARSEAPI +#define XMLPARSEAPI /* as nothing */ +#endif + +typedef void *XML_Parser; + +#ifdef XML_UNICODE_WCHAR_T + +/* XML_UNICODE_WCHAR_T will work only if sizeof(wchar_t) == 2 and wchar_t +uses Unicode. */ +/* Information is UTF-16 encoded as wchar_ts */ + +#ifndef XML_UNICODE +#define XML_UNICODE +#endif + +#include +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; + +#else /* not XML_UNICODE_WCHAR_T */ + +#ifdef XML_UNICODE + +/* Information is UTF-16 encoded as unsigned shorts */ +typedef unsigned short XML_Char; +typedef char XML_LChar; + +#else /* not XML_UNICODE */ + +/* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; + +#endif /* not XML_UNICODE */ + +#endif /* not XML_UNICODE_WCHAR_T */ + + +/* Constructs a new parser; encoding is the encoding specified by the external +protocol or null if there is none specified. */ + +XML_Parser XMLPARSEAPI +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type names +and attribute names that belong to a namespace will be expanded; +unprefixed attribute names are never expanded; unprefixed element type +names are expanded only if there is a default namespace. The expanded +name is the concatenation of the namespace URI, the namespace separator character, +and the local part of the name. If the namespace separator is '\0' then +the namespace URI and the local part will be concatenated without any +separator. When a namespace is not declared, the name and prefix will be +passed through without expansion. */ + +XML_Parser XMLPARSEAPI +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. */ + +typedef void (*XML_StartElementHandler)(void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (*XML_EndElementHandler)(void *userData, + const XML_Char *name); + +/* s is not 0 terminated. */ +typedef void (*XML_CharacterDataHandler)(void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (*XML_ProcessingInstructionHandler)(void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (*XML_CommentHandler)(void *userData, const XML_Char *data); + +typedef void (*XML_StartCdataSectionHandler)(void *userData); +typedef void (*XML_EndCdataSectionHandler)(void *userData); + +/* This is called for any characters in the XML document for +which there is no applicable handler. This includes both +characters that are part of markup which is of a kind that is +not reported (comments, markup declarations), or characters +that are part of a construct which could be reported but +for which no handler has been supplied. The characters are passed +exactly as they were in the XML document except that +they will be encoded in UTF-8. Line boundaries are not normalized. +Note that a byte order mark character is not passed to the default handler. +There are no guarantees about how characters are divided between calls +to the default handler: for example, a comment might be split between +multiple calls. */ + +typedef void (*XML_DefaultHandler)(void *userData, + const XML_Char *s, + int len); + +/* This is called for a declaration of an unparsed (NDATA) +entity. The base argument is whatever was set by XML_SetBase. +The entityName, systemId and notationName arguments will never be null. +The other arguments may be. */ + +typedef void (*XML_UnparsedEntityDeclHandler)(void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. +The base argument is whatever was set by XML_SetBase. +The notationName will never be null. The other arguments can be. */ + +typedef void (*XML_NotationDeclHandler)(void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for +each namespace declaration. The call to the start and end element +handlers occur between the calls to the start and end namespace +declaration handlers. For an xmlns attribute, prefix will be null. +For an xmlns="" attribute, uri will be null. */ + +typedef void (*XML_StartNamespaceDeclHandler)(void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (*XML_EndNamespaceDeclHandler)(void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone (it has an +external subset or a reference to a parameter entity, but does not +have standalone="yes"). If this handler returns 0, then processing +will not continue, and the parser will return a +XML_ERROR_NOT_STANDALONE error. */ + +typedef int (*XML_NotStandaloneHandler)(void *userData); + +/* This is called for a reference to an external parsed general entity. +The referenced entity is not automatically parsed. +The application can parse it immediately or later using +XML_ExternalEntityParserCreate. +The parser argument is the parser parsing the entity containing the reference; +it can be passed as the parser argument to XML_ExternalEntityParserCreate. +The systemId argument is the system identifier as specified in the entity declaration; +it will not be null. +The base argument is the system identifier that should be used as the base for +resolving systemId if systemId was relative; this is set by XML_SetBase; +it may be null. +The publicId argument is the public identifier as specified in the entity declaration, +or null if none was specified; the whitespace in the public identifier +will have been normalized as required by the XML spec. +The context argument specifies the parsing context in the format +expected by the context argument to +XML_ExternalEntityParserCreate; context is valid only until the handler +returns, so if the referenced entity is to be parsed later, it must be copied. +The handler should return 0 if processing should not continue because of +a fatal error in the handling of the external entity. +In this case the calling parser will return an XML_ERROR_EXTERNAL_ENTITY_HANDLING +error. +Note that unlike other handlers the first argument is the parser, not userData. */ + +typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This structure is filled in by the XML_UnknownEncodingHandler +to provide information to the parser about encodings that are unknown +to the parser. +The map[b] member gives information about byte sequences +whose first byte is b. +If map[b] is c where c is >= 0, then b by itself encodes the Unicode scalar value c. +If map[b] is -1, then the byte sequence is malformed. +If map[b] is -n, where n >= 2, then b is the first byte of an n-byte +sequence that encodes a single Unicode scalar value. +The data member will be passed as the first argument to the convert function. +The convert function is used to convert multibyte sequences; +s will point to a n-byte sequence where map[(unsigned char)*s] == -n. +The convert function must return the Unicode scalar value +represented by this byte sequence or -1 if the byte sequence is malformed. +The convert function may be null if the encoding is a single-byte encoding, +that is if map[b] >= -1 for all bytes b. +When the parser is finished with the encoding, then if release is not null, +it will call release passing it the data member; +once release has been called, the convert function will not be called again. + +Expat places certain restrictions on the encodings that are supported +using this mechanism. + +1. Every ASCII character that can appear in a well-formed XML document, +other than the characters + + $@\^`{}~ + +must be represented by a single byte, and that byte must be the +same byte that represents that character in ASCII. + +2. No character may require more than 4 bytes to encode. + +3. All characters encoded must have Unicode scalar values <= 0xFFFF, +(ie characters that would be encoded by surrogates in UTF-16 +are not allowed). Note that this restriction doesn't apply to +the built-in support for UTF-8 and UTF-16. + +4. No Unicode character may be encoded by more than one distinct sequence +of bytes. */ + +typedef struct { + int map[256]; + void *data; + int (*convert)(void *data, const char *s); + void (*release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. +The encodingHandlerData argument is that which was passed as the +second argument to XML_SetUnknownEncodingHandler. +The name argument gives the name of the encoding as specified in +the encoding declaration. +If the callback can provide information about the encoding, +it must fill in the XML_Encoding structure, and return 1. +Otherwise it must return 0. +If info does not describe a suitable encoding, +then the parser will return an XML_UNKNOWN_ENCODING error. */ + +typedef int (*XML_UnknownEncodingHandler)(void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +void XMLPARSEAPI +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +void XMLPARSEAPI +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +void XMLPARSEAPI +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +void XMLPARSEAPI +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +void XMLPARSEAPI +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of internal entities. +The entity reference will be passed to the default handler. */ + +void XMLPARSEAPI +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of internal entities. +The entity reference will not be passed to the default handler. */ + +void XMLPARSEAPI +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +void XMLPARSEAPI +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +void XMLPARSEAPI +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +void XMLPARSEAPI +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +void XMLPARSEAPI +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +void XMLPARSEAPI +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-null value for arg is specified here, then it will be passed +as the first argument to the external entity ref handler instead +of the parser object. */ +void XMLPARSEAPI +XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg); + +void XMLPARSEAPI +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end element, +processing instruction or character data. It causes the corresponding +markup to be passed to the default handler. */ +void XMLPARSEAPI XML_DefaultCurrent(XML_Parser parser); + +/* This value is passed as the userData argument to callbacks. */ +void XMLPARSEAPI +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or null. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument +to XML_CreateParser. It must not be called after XML_Parse +or XML_ParseBuffer. */ + +int XMLPARSEAPI +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed +as the first argument to callbacks instead of userData. +The userData will still be accessible using XML_GetUserData. */ + +void XMLPARSEAPI +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* Sets the base to be used for resolving relative URIs in system identifiers in +declarations. Resolving relative identifiers is left to the application: +this value will be passed through as the base argument to the +XML_ExternalEntityRefHandler, XML_NotationDeclHandler +and XML_UnparsedEntityDeclHandler. The base argument will be copied. +Returns zero if out of memory, non-zero otherwise. */ + +int XMLPARSEAPI +XML_SetBase(XML_Parser parser, const XML_Char *base); + +const XML_Char XMLPARSEAPI * +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attributes passed in last call to the +XML_StartElementHandler that were specified in the start-tag rather +than defaulted. */ + +int XMLPARSEAPI XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Parses some input. Returns 0 if a fatal error is detected. +The last call to XML_Parse must have isFinal true; +len may be zero for this call (or any other). */ +int XMLPARSEAPI +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +void XMLPARSEAPI * +XML_GetBuffer(XML_Parser parser, int len); + +int XMLPARSEAPI +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Creates an XML_Parser object that can parse an external general entity; +context is a '\0'-terminated string specifying the parse context; +encoding is a '\0'-terminated string giving the name of the externally specified encoding, +or null if there is no externally specified encoding. +The context string consists of a sequence of tokens separated by formfeeds (\f); +a token consisting of a name specifies that the general entity of the name +is open; a token of the form prefix=uri specifies the namespace for a particular +prefix; a token of the form =uri specifies the default namespace. +This can be called at any point after the first call to an ExternalEntityRefHandler +so longer as the parser has not yet been freed. +The new parser is completely independent and may safely be used in a separate thread. +The handlers and userData are initialized from the parser argument. +Returns 0 if out of memory. Otherwise returns a new XML_Parser object. */ +XML_Parser XMLPARSEAPI +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE +}; + +/* If XML_Parse or XML_ParseBuffer have returned 0, then XML_GetErrorCode +returns information about the error. */ + +enum XML_Error XMLPARSEAPI XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse location. +They may be called when XML_Parse or XML_ParseBuffer return 0; +in this case the location is the location of the character at which +the error was detected. +They may also be called from any other callback called to report +some parse event; in this the location is the location of the first +of the sequence of characters that generated the event. */ + +int XMLPARSEAPI XML_GetCurrentLineNumber(XML_Parser parser); +int XMLPARSEAPI XML_GetCurrentColumnNumber(XML_Parser parser); +long XMLPARSEAPI XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. +Returns 0 if the event is in an internal entity. */ + +int XMLPARSEAPI XML_GetCurrentByteCount(XML_Parser parser); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees memory used by the parser. */ +void XMLPARSEAPI +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +const XML_LChar XMLPARSEAPI *XML_ErrorString(int code); + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlParse_INCLUDED */ diff -Nru simgear-2.10.0/3rdparty/expat/xmlrole.c simgear-3.0.0/3rdparty/expat/xmlrole.c --- simgear-2.10.0/3rdparty/expat/xmlrole.c 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/xmlrole.c 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,1336 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include + +#ifdef COMPILED_FROM_DSP +#include "winconfig.h" +#elif defined(MACOS_CLASSIC) +#include "macconfig.h" +#elif defined(__amigaos__) +#include "amigaconfig.h" +#elif defined(__WATCOMC__) +#include "watcomconfig.h" +#else +#ifdef HAVE_EXPAT_CONFIG_H +#include "expat_config.h" +#endif +#endif /* ndef COMPILED_FROM_DSP */ + +#include "sg_expat_external.h" +#include "internal.h" +#include "xmlrole.h" +#include "ascii.h" + +/* Doesn't check: + + that ,| are not mixed in a model group + content of literals + +*/ + +static const char KW_ANY[] = { + ASCII_A, ASCII_N, ASCII_Y, '\0' }; +static const char KW_ATTLIST[] = { + ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' }; +static const char KW_CDATA[] = { + ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_DOCTYPE[] = { + ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' }; +static const char KW_ELEMENT[] = { + ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' }; +static const char KW_EMPTY[] = { + ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' }; +static const char KW_ENTITIES[] = { + ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, + '\0' }; +static const char KW_ENTITY[] = { + ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' }; +static const char KW_FIXED[] = { + ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' }; +static const char KW_ID[] = { + ASCII_I, ASCII_D, '\0' }; +static const char KW_IDREF[] = { + ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' }; +static const char KW_IDREFS[] = { + ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' }; +#ifdef XML_DTD +static const char KW_IGNORE[] = { + ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' }; +#endif +static const char KW_IMPLIED[] = { + ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' }; +#ifdef XML_DTD +static const char KW_INCLUDE[] = { + ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' }; +#endif +static const char KW_NDATA[] = { + ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_NMTOKEN[] = { + ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' }; +static const char KW_NMTOKENS[] = { + ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, + '\0' }; +static const char KW_NOTATION[] = + { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, + '\0' }; +static const char KW_PCDATA[] = { + ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_PUBLIC[] = { + ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' }; +static const char KW_REQUIRED[] = { + ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D, + '\0' }; +static const char KW_SYSTEM[] = { + ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' }; + +#ifndef MIN_BYTES_PER_CHAR +#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar) +#endif + +#ifdef XML_DTD +#define setTopLevel(state) \ + ((state)->handler = ((state)->documentEntity \ + ? internalSubset \ + : externalSubset1)) +#else /* not XML_DTD */ +#define setTopLevel(state) ((state)->handler = internalSubset) +#endif /* not XML_DTD */ + +typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + +static PROLOG_HANDLER + prolog0, prolog1, prolog2, + doctype0, doctype1, doctype2, doctype3, doctype4, doctype5, + internalSubset, + entity0, entity1, entity2, entity3, entity4, entity5, entity6, + entity7, entity8, entity9, entity10, + notation0, notation1, notation2, notation3, notation4, + attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6, + attlist7, attlist8, attlist9, + element0, element1, element2, element3, element4, element5, element6, + element7, +#ifdef XML_DTD + externalSubset0, externalSubset1, + condSect0, condSect1, condSect2, +#endif /* XML_DTD */ + declClose, + error; + +static int FASTCALL common(PROLOG_STATE *state, int tok); + +static int PTRCALL +prolog0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + state->handler = prolog1; + return XML_ROLE_NONE; + case XML_TOK_XML_DECL: + state->handler = prolog1; + return XML_ROLE_XML_DECL; + case XML_TOK_PI: + state->handler = prolog1; + return XML_ROLE_PI; + case XML_TOK_COMMENT: + state->handler = prolog1; + return XML_ROLE_COMMENT; + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +prolog1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +prolog2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +doctype0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = doctype1; + return XML_ROLE_DOCTYPE_NAME; + } + return common(state, tok); +} + +static int PTRCALL +doctype1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = doctype3; + return XML_ROLE_DOCTYPE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = doctype2; + return XML_ROLE_DOCTYPE_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +doctype2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype3; + return XML_ROLE_DOCTYPE_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +doctype3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype4; + return XML_ROLE_DOCTYPE_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +doctype4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static int PTRCALL +doctype5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static int PTRCALL +internalSubset(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ENTITY)) { + state->handler = entity0; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ATTLIST)) { + state->handler = attlist0; + return XML_ROLE_ATTLIST_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ELEMENT)) { + state->handler = element0; + return XML_ROLE_ELEMENT_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_NOTATION)) { + state->handler = notation0; + return XML_ROLE_NOTATION_NONE; + } + break; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_PARAM_ENTITY_REF: + return XML_ROLE_PARAM_ENTITY_REF; + case XML_TOK_CLOSE_BRACKET: + state->handler = doctype5; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_NONE: + return XML_ROLE_NONE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static int PTRCALL +externalSubset0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + state->handler = externalSubset1; + if (tok == XML_TOK_XML_DECL) + return XML_ROLE_TEXT_DECL; + return externalSubset1(state, tok, ptr, end, enc); +} + +static int PTRCALL +externalSubset1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_COND_SECT_OPEN: + state->handler = condSect0; + return XML_ROLE_NONE; + case XML_TOK_COND_SECT_CLOSE: + if (state->includeLevel == 0) + break; + state->includeLevel -= 1; + return XML_ROLE_NONE; + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_BRACKET: + break; + case XML_TOK_NONE: + if (state->includeLevel) + break; + return XML_ROLE_NONE; + default: + return internalSubset(state, tok, ptr, end, enc); + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static int PTRCALL +entity0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_PERCENT: + state->handler = entity1; + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = entity2; + return XML_ROLE_GENERAL_ENTITY_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = entity7; + return XML_ROLE_PARAM_ENTITY_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity4; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity3; + return XML_ROLE_ENTITY_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +entity3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity4; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity5; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ENTITY_COMPLETE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) { + state->handler = entity6; + return XML_ROLE_ENTITY_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +entity6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_NOTATION_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity9; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity8; + return XML_ROLE_ENTITY_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +entity8(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity9; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity9(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity10; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity10(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ENTITY_COMPLETE; + } + return common(state, tok); +} + +static int PTRCALL +notation0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_NAME: + state->handler = notation1; + return XML_ROLE_NOTATION_NAME; + } + return common(state, tok); +} + +static int PTRCALL +notation1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = notation3; + return XML_ROLE_NOTATION_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = notation2; + return XML_ROLE_NOTATION_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +notation2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = notation4; + return XML_ROLE_NOTATION_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +notation3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_NOTATION_NONE; + return XML_ROLE_NOTATION_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +notation4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_NOTATION_NONE; + return XML_ROLE_NOTATION_SYSTEM_ID; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_NOTATION_NO_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +attlist0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist1; + return XML_ROLE_ATTLIST_ELEMENT_NAME; + } + return common(state, tok); +} + +static int PTRCALL +attlist1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist2; + return XML_ROLE_ATTRIBUTE_NAME; + } + return common(state, tok); +} + +static int PTRCALL +attlist2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + { + static const char * const types[] = { + KW_CDATA, + KW_ID, + KW_IDREF, + KW_IDREFS, + KW_ENTITY, + KW_ENTITIES, + KW_NMTOKEN, + KW_NMTOKENS, + }; + int i; + for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++) + if (XmlNameMatchesAscii(enc, ptr, end, types[i])) { + state->handler = attlist8; + return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i; + } + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) { + state->handler = attlist5; + return XML_ROLE_ATTLIST_NONE; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = attlist3; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NMTOKEN: + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist4; + return XML_ROLE_ATTRIBUTE_ENUM_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OR: + state->handler = attlist3; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OPEN_PAREN: + state->handler = attlist6; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + state->handler = attlist7; + return XML_ROLE_ATTRIBUTE_NOTATION_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OR: + state->handler = attlist6; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +/* default value */ +static int PTRCALL +attlist8(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_IMPLIED)) { + state->handler = attlist1; + return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_REQUIRED)) { + state->handler = attlist1; + return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_FIXED)) { + state->handler = attlist9; + return XML_ROLE_ATTLIST_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist9(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_FIXED_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +element0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element1; + return XML_ROLE_ELEMENT_NAME; + } + return common(state, tok); +} + +static int PTRCALL +element1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_CONTENT_EMPTY; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_CONTENT_ANY; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = element2; + state->level = 1; + return XML_ROLE_GROUP_OPEN; + } + return common(state, tok); +} + +static int PTRCALL +element2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_PCDATA)) { + state->handler = element3; + return XML_ROLE_CONTENT_PCDATA; + } + break; + case XML_TOK_OPEN_PAREN: + state->level = 2; + state->handler = element6; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static int PTRCALL +element3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_ELEMENT_NONE; + } + return common(state, tok); +} + +static int PTRCALL +element4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element5; + return XML_ROLE_CONTENT_ELEMENT; + } + return common(state, tok); +} + +static int PTRCALL +element5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_ELEMENT_NONE; + } + return common(state, tok); +} + +static int PTRCALL +element6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_OPEN_PAREN: + state->level += 1; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static int PTRCALL +element7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_CLOSE_PAREN_QUESTION: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_OPT; + case XML_TOK_CLOSE_PAREN_PLUS: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_PLUS; + case XML_TOK_COMMA: + state->handler = element6; + return XML_ROLE_GROUP_SEQUENCE; + case XML_TOK_OR: + state->handler = element6; + return XML_ROLE_GROUP_CHOICE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static int PTRCALL +condSect0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) { + state->handler = condSect1; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) { + state->handler = condSect2; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +condSect1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + state->includeLevel += 1; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static int PTRCALL +condSect2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + return XML_ROLE_IGNORE_SECT; + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static int PTRCALL +declClose(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return state->role_none; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return state->role_none; + } + return common(state, tok); +} + +static int PTRCALL +error(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + return XML_ROLE_NONE; +} + +static int FASTCALL +common(PROLOG_STATE *state, int tok) +{ +#ifdef XML_DTD + if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF) + return XML_ROLE_INNER_PARAM_ENTITY_REF; +#endif + state->handler = error; + return XML_ROLE_ERROR; +} + +void +XmlPrologStateInit(PROLOG_STATE *state) +{ + state->handler = prolog0; +#ifdef XML_DTD + state->documentEntity = 1; + state->includeLevel = 0; + state->inEntityValue = 0; +#endif /* XML_DTD */ +} + +#ifdef XML_DTD + +void +XmlPrologStateInitExternalEntity(PROLOG_STATE *state) +{ + state->handler = externalSubset0; + state->documentEntity = 0; + state->includeLevel = 0; +} + +#endif /* XML_DTD */ diff -Nru simgear-2.10.0/3rdparty/expat/xmlrole.h simgear-3.0.0/3rdparty/expat/xmlrole.h --- simgear-2.10.0/3rdparty/expat/xmlrole.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/xmlrole.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,114 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef XmlRole_INCLUDED +#define XmlRole_INCLUDED 1 + +#ifdef __VMS +/* 0 1 2 3 0 1 2 3 + 1234567890123456789012345678901 1234567890123456789012345678901 */ +#define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt +#endif + +#include "xmltok.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + XML_ROLE_ERROR = -1, + XML_ROLE_NONE = 0, + XML_ROLE_XML_DECL, + XML_ROLE_INSTANCE_START, + XML_ROLE_DOCTYPE_NONE, + XML_ROLE_DOCTYPE_NAME, + XML_ROLE_DOCTYPE_SYSTEM_ID, + XML_ROLE_DOCTYPE_PUBLIC_ID, + XML_ROLE_DOCTYPE_INTERNAL_SUBSET, + XML_ROLE_DOCTYPE_CLOSE, + XML_ROLE_GENERAL_ENTITY_NAME, + XML_ROLE_PARAM_ENTITY_NAME, + XML_ROLE_ENTITY_NONE, + XML_ROLE_ENTITY_VALUE, + XML_ROLE_ENTITY_SYSTEM_ID, + XML_ROLE_ENTITY_PUBLIC_ID, + XML_ROLE_ENTITY_COMPLETE, + XML_ROLE_ENTITY_NOTATION_NAME, + XML_ROLE_NOTATION_NONE, + XML_ROLE_NOTATION_NAME, + XML_ROLE_NOTATION_SYSTEM_ID, + XML_ROLE_NOTATION_NO_SYSTEM_ID, + XML_ROLE_NOTATION_PUBLIC_ID, + XML_ROLE_ATTRIBUTE_NAME, + XML_ROLE_ATTRIBUTE_TYPE_CDATA, + XML_ROLE_ATTRIBUTE_TYPE_ID, + XML_ROLE_ATTRIBUTE_TYPE_IDREF, + XML_ROLE_ATTRIBUTE_TYPE_IDREFS, + XML_ROLE_ATTRIBUTE_TYPE_ENTITY, + XML_ROLE_ATTRIBUTE_TYPE_ENTITIES, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS, + XML_ROLE_ATTRIBUTE_ENUM_VALUE, + XML_ROLE_ATTRIBUTE_NOTATION_VALUE, + XML_ROLE_ATTLIST_NONE, + XML_ROLE_ATTLIST_ELEMENT_NAME, + XML_ROLE_IMPLIED_ATTRIBUTE_VALUE, + XML_ROLE_REQUIRED_ATTRIBUTE_VALUE, + XML_ROLE_DEFAULT_ATTRIBUTE_VALUE, + XML_ROLE_FIXED_ATTRIBUTE_VALUE, + XML_ROLE_ELEMENT_NONE, + XML_ROLE_ELEMENT_NAME, + XML_ROLE_CONTENT_ANY, + XML_ROLE_CONTENT_EMPTY, + XML_ROLE_CONTENT_PCDATA, + XML_ROLE_GROUP_OPEN, + XML_ROLE_GROUP_CLOSE, + XML_ROLE_GROUP_CLOSE_REP, + XML_ROLE_GROUP_CLOSE_OPT, + XML_ROLE_GROUP_CLOSE_PLUS, + XML_ROLE_GROUP_CHOICE, + XML_ROLE_GROUP_SEQUENCE, + XML_ROLE_CONTENT_ELEMENT, + XML_ROLE_CONTENT_ELEMENT_REP, + XML_ROLE_CONTENT_ELEMENT_OPT, + XML_ROLE_CONTENT_ELEMENT_PLUS, + XML_ROLE_PI, + XML_ROLE_COMMENT, +#ifdef XML_DTD + XML_ROLE_TEXT_DECL, + XML_ROLE_IGNORE_SECT, + XML_ROLE_INNER_PARAM_ENTITY_REF, +#endif /* XML_DTD */ + XML_ROLE_PARAM_ENTITY_REF +}; + +typedef struct prolog_state { + int (PTRCALL *handler) (struct prolog_state *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + unsigned level; + int role_none; +#ifdef XML_DTD + unsigned includeLevel; + int documentEntity; + int inEntityValue; +#endif /* XML_DTD */ +} PROLOG_STATE; + +void XmlPrologStateInit(PROLOG_STATE *); +#ifdef XML_DTD +void XmlPrologStateInitExternalEntity(PROLOG_STATE *); +#endif /* XML_DTD */ + +#define XmlTokenRole(state, tok, ptr, end, enc) \ + (((state)->handler)(state, tok, ptr, end, enc)) + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlRole_INCLUDED */ diff -Nru simgear-2.10.0/3rdparty/expat/xmltok.c simgear-3.0.0/3rdparty/expat/xmltok.c --- simgear-2.10.0/3rdparty/expat/xmltok.c 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/xmltok.c 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,1651 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#include + +#ifdef COMPILED_FROM_DSP +#include "winconfig.h" +#elif defined(MACOS_CLASSIC) +#include "macconfig.h" +#elif defined(__amigaos__) +#include "amigaconfig.h" +#elif defined(__WATCOMC__) +#include "watcomconfig.h" +#else +#ifdef HAVE_EXPAT_CONFIG_H +#include "expat_config.h" +#endif +#endif /* ndef COMPILED_FROM_DSP */ + +#include "sg_expat_external.h" +#include "internal.h" +#include "xmltok.h" +#include "nametab.h" + +#ifdef XML_DTD +#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok) +#else +#define IGNORE_SECTION_TOK_VTABLE /* as nothing */ +#endif + +#define VTABLE1 \ + { PREFIX(prologTok), PREFIX(contentTok), \ + PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \ + { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \ + PREFIX(sameName), \ + PREFIX(nameMatchesAscii), \ + PREFIX(nameLength), \ + PREFIX(skipS), \ + PREFIX(getAtts), \ + PREFIX(charRefNumber), \ + PREFIX(predefinedEntityName), \ + PREFIX(updatePosition), \ + PREFIX(isPublicId) + +#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16) + +#define UCS2_GET_NAMING(pages, hi, lo) \ + (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F))) + +/* A 2 byte UTF-8 representation splits the characters 11 bits between + the bottom 5 and 6 bits of the bytes. We need 8 bits to index into + pages, 3 bits to add to that index and 5 bits to generate the mask. +*/ +#define UTF8_GET_NAMING2(pages, byte) \ + (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ + + ((((byte)[0]) & 3) << 1) \ + + ((((byte)[1]) >> 5) & 1)] \ + & (1 << (((byte)[1]) & 0x1F))) + +/* A 3 byte UTF-8 representation splits the characters 16 bits between + the bottom 4, 6 and 6 bits of the bytes. We need 8 bits to index + into pages, 3 bits to add to that index and 5 bits to generate the + mask. +*/ +#define UTF8_GET_NAMING3(pages, byte) \ + (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ + + ((((byte)[1]) >> 2) & 0xF)] \ + << 3) \ + + ((((byte)[1]) & 3) << 1) \ + + ((((byte)[2]) >> 5) & 1)] \ + & (1 << (((byte)[2]) & 0x1F))) + +#define UTF8_GET_NAMING(pages, p, n) \ + ((n) == 2 \ + ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \ + : ((n) == 3 \ + ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \ + : 0)) + +/* Detection of invalid UTF-8 sequences is based on Table 3.1B + of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/ + with the additional restriction of not allowing the Unicode + code points 0xFFFF and 0xFFFE (sequences EF,BF,BF and EF,BF,BE). + Implementation details: + (A & 0x80) == 0 means A < 0x80 + and + (A & 0xC0) == 0xC0 means A > 0xBF +*/ + +#define UTF8_INVALID2(p) \ + ((*p) < 0xC2 || ((p)[1] & 0x80) == 0 || ((p)[1] & 0xC0) == 0xC0) + +#define UTF8_INVALID3(p) \ + (((p)[2] & 0x80) == 0 \ + || \ + ((*p) == 0xEF && (p)[1] == 0xBF \ + ? \ + (p)[2] > 0xBD \ + : \ + ((p)[2] & 0xC0) == 0xC0) \ + || \ + ((*p) == 0xE0 \ + ? \ + (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \ + : \ + ((p)[1] & 0x80) == 0 \ + || \ + ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0))) + +#define UTF8_INVALID4(p) \ + (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 \ + || \ + ((p)[2] & 0x80) == 0 || ((p)[2] & 0xC0) == 0xC0 \ + || \ + ((*p) == 0xF0 \ + ? \ + (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \ + : \ + ((p)[1] & 0x80) == 0 \ + || \ + ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0))) + +static int PTRFASTCALL +isNever(const ENCODING *enc, const char *p) +{ + return 0; +} + +static int PTRFASTCALL +utf8_isName2(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING2(namePages, (const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isName3(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING3(namePages, (const unsigned char *)p); +} + +#define utf8_isName4 isNever + +static int PTRFASTCALL +utf8_isNmstrt2(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isNmstrt3(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p); +} + +#define utf8_isNmstrt4 isNever + +static int PTRFASTCALL +utf8_isInvalid2(const ENCODING *enc, const char *p) +{ + return UTF8_INVALID2((const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isInvalid3(const ENCODING *enc, const char *p) +{ + return UTF8_INVALID3((const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isInvalid4(const ENCODING *enc, const char *p) +{ + return UTF8_INVALID4((const unsigned char *)p); +} + +struct normal_encoding { + ENCODING enc; + unsigned char type[256]; +#ifdef XML_MIN_SIZE + int (PTRFASTCALL *byteType)(const ENCODING *, const char *); + int (PTRFASTCALL *isNameMin)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *); + int (PTRFASTCALL *byteToAscii)(const ENCODING *, const char *); + int (PTRCALL *charMatches)(const ENCODING *, const char *, int); +#endif /* XML_MIN_SIZE */ + int (PTRFASTCALL *isName2)(const ENCODING *, const char *); + int (PTRFASTCALL *isName3)(const ENCODING *, const char *); + int (PTRFASTCALL *isName4)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *); + int (PTRFASTCALL *isInvalid2)(const ENCODING *, const char *); + int (PTRFASTCALL *isInvalid3)(const ENCODING *, const char *); + int (PTRFASTCALL *isInvalid4)(const ENCODING *, const char *); +}; + +#define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *) (enc)) + +#ifdef XML_MIN_SIZE + +#define STANDARD_VTABLE(E) \ + E ## byteType, \ + E ## isNameMin, \ + E ## isNmstrtMin, \ + E ## byteToAscii, \ + E ## charMatches, + +#else + +#define STANDARD_VTABLE(E) /* as nothing */ + +#endif + +#define NORMAL_VTABLE(E) \ + E ## isName2, \ + E ## isName3, \ + E ## isName4, \ + E ## isNmstrt2, \ + E ## isNmstrt3, \ + E ## isNmstrt4, \ + E ## isInvalid2, \ + E ## isInvalid3, \ + E ## isInvalid4 + +static int FASTCALL checkCharRefNumber(int); + +#include "xmltok_impl.h" +#include "ascii.h" + +#ifdef XML_MIN_SIZE +#define sb_isNameMin isNever +#define sb_isNmstrtMin isNever +#endif + +#ifdef XML_MIN_SIZE +#define MINBPC(enc) ((enc)->minBytesPerChar) +#else +/* minimum bytes per character */ +#define MINBPC(enc) 1 +#endif + +#define SB_BYTE_TYPE(enc, p) \ + (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)]) + +#ifdef XML_MIN_SIZE +static int PTRFASTCALL +sb_byteType(const ENCODING *enc, const char *p) +{ + return SB_BYTE_TYPE(enc, p); +} +#define BYTE_TYPE(enc, p) \ + (AS_NORMAL_ENCODING(enc)->byteType(enc, p)) +#else +#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p) +#endif + +#ifdef XML_MIN_SIZE +#define BYTE_TO_ASCII(enc, p) \ + (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p)) +static int PTRFASTCALL +sb_byteToAscii(const ENCODING *enc, const char *p) +{ + return *p; +} +#else +#define BYTE_TO_ASCII(enc, p) (*(p)) +#endif + +#define IS_NAME_CHAR(enc, p, n) \ + (AS_NORMAL_ENCODING(enc)->isName ## n(enc, p)) +#define IS_NMSTRT_CHAR(enc, p, n) \ + (AS_NORMAL_ENCODING(enc)->isNmstrt ## n(enc, p)) +#define IS_INVALID_CHAR(enc, p, n) \ + (AS_NORMAL_ENCODING(enc)->isInvalid ## n(enc, p)) + +#ifdef XML_MIN_SIZE +#define IS_NAME_CHAR_MINBPC(enc, p) \ + (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p)) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) \ + (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p)) +#else +#define IS_NAME_CHAR_MINBPC(enc, p) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0) +#endif + +#ifdef XML_MIN_SIZE +#define CHAR_MATCHES(enc, p, c) \ + (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c)) +static int PTRCALL +sb_charMatches(const ENCODING *enc, const char *p, int c) +{ + return *p == c; +} +#else +/* c is an ASCII character */ +#define CHAR_MATCHES(enc, p, c) (*(p) == c) +#endif + +#define PREFIX(ident) normal_ ## ident +#define XML_TOK_IMPL_C +#include "xmltok_impl.c" +#undef XML_TOK_IMPL_C + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */ + UTF8_cval1 = 0x00, + UTF8_cval2 = 0xc0, + UTF8_cval3 = 0xe0, + UTF8_cval4 = 0xf0 +}; + +static void PTRCALL +utf8_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + char *to; + const char *from; + if (fromLim - *fromP > toLim - *toP) { + /* Avoid copying partial characters. */ + for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--) + if (((unsigned char)fromLim[-1] & 0xc0) != 0x80) + break; + } + for (to = *toP, from = *fromP; from != fromLim; from++, to++) + *to = *from; + *fromP = from; + *toP = to; +} + +static void PTRCALL +utf8_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + unsigned short *to = *toP; + const char *from = *fromP; + while (from != fromLim && to != toLim) { + switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) { + case BT_LEAD2: + *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f)); + from += 2; + break; + case BT_LEAD3: + *to++ = (unsigned short)(((from[0] & 0xf) << 12) + | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f)); + from += 3; + break; + case BT_LEAD4: + { + unsigned long n; + if (to + 1 == toLim) + goto after; + n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) + | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f); + n -= 0x10000; + to[0] = (unsigned short)((n >> 10) | 0xD800); + to[1] = (unsigned short)((n & 0x3FF) | 0xDC00); + to += 2; + from += 4; + } + break; + default: + *to++ = *from++; + break; + } + } +after: + *fromP = from; + *toP = to; +} + +#ifdef XML_NS +static const struct normal_encoding utf8_encoding_ns = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; +#endif + +static const struct normal_encoding utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +#ifdef XML_NS + +static const struct normal_encoding internal_utf8_encoding_ns = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "iasciitab.h" +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +#endif + +static const struct normal_encoding internal_utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +static void PTRCALL +latin1_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + for (;;) { + unsigned char c; + if (*fromP == fromLim) + break; + c = (unsigned char)**fromP; + if (c & 0x80) { + if (toLim - *toP < 2) + break; + *(*toP)++ = (char)((c >> 6) | UTF8_cval2); + *(*toP)++ = (char)((c & 0x3f) | 0x80); + (*fromP)++; + } + else { + if (*toP == toLim) + break; + *(*toP)++ = *(*fromP)++; + } + } +} + +static void PTRCALL +latin1_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = (unsigned char)*(*fromP)++; +} + +#ifdef XML_NS + +static const struct normal_encoding latin1_encoding_ns = { + { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) +}; + +#endif + +static const struct normal_encoding latin1_encoding = { + { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) +}; + +static void PTRCALL +ascii_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = *(*fromP)++; +} + +#ifdef XML_NS + +static const struct normal_encoding ascii_encoding_ns = { + { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +/* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) +}; + +#endif + +static const struct normal_encoding ascii_encoding = { + { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +/* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) +}; + +static int PTRFASTCALL +unicode_byte_type(char hi, char lo) +{ + switch ((unsigned char)hi) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + return BT_LEAD4; + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return BT_TRAIL; + case 0xFF: + switch ((unsigned char)lo) { + case 0xFF: + case 0xFE: + return BT_NONXML; + } + break; + } + return BT_NONASCII; +} + +#define DEFINE_UTF16_TO_UTF8(E) \ +static void PTRCALL \ +E ## toUtf8(const ENCODING *enc, \ + const char **fromP, const char *fromLim, \ + char **toP, const char *toLim) \ +{ \ + const char *from; \ + for (from = *fromP; from != fromLim; from += 2) { \ + int plane; \ + unsigned char lo2; \ + unsigned char lo = GET_LO(from); \ + unsigned char hi = GET_HI(from); \ + switch (hi) { \ + case 0: \ + if (lo < 0x80) { \ + if (*toP == toLim) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = lo; \ + break; \ + } \ + /* fall through */ \ + case 0x1: case 0x2: case 0x3: \ + case 0x4: case 0x5: case 0x6: case 0x7: \ + if (toLim - *toP < 2) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + default: \ + if (toLim - *toP < 3) { \ + *fromP = from; \ + return; \ + } \ + /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \ + *(*toP)++ = ((hi >> 4) | UTF8_cval3); \ + *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + case 0xD8: case 0xD9: case 0xDA: case 0xDB: \ + if (toLim - *toP < 4) { \ + *fromP = from; \ + return; \ + } \ + plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \ + *(*toP)++ = ((plane >> 2) | UTF8_cval4); \ + *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \ + from += 2; \ + lo2 = GET_LO(from); \ + *(*toP)++ = (((lo & 0x3) << 4) \ + | ((GET_HI(from) & 0x3) << 2) \ + | (lo2 >> 6) \ + | 0x80); \ + *(*toP)++ = ((lo2 & 0x3f) | 0x80); \ + break; \ + } \ + } \ + *fromP = from; \ +} + +#define DEFINE_UTF16_TO_UTF16(E) \ +static void PTRCALL \ +E ## toUtf16(const ENCODING *enc, \ + const char **fromP, const char *fromLim, \ + unsigned short **toP, const unsigned short *toLim) \ +{ \ + /* Avoid copying first half only of surrogate */ \ + if (fromLim - *fromP > ((toLim - *toP) << 1) \ + && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \ + fromLim -= 2; \ + for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \ + *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \ +} + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8))) +#define GET_LO(ptr) ((unsigned char)(ptr)[0]) +#define GET_HI(ptr) ((unsigned char)(ptr)[1]) + +DEFINE_UTF16_TO_UTF8(little2_) +DEFINE_UTF16_TO_UTF16(little2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF))) +#define GET_LO(ptr) ((unsigned char)(ptr)[1]) +#define GET_HI(ptr) ((unsigned char)(ptr)[0]) + +DEFINE_UTF16_TO_UTF8(big2_) +DEFINE_UTF16_TO_UTF16(big2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define LITTLE2_BYTE_TYPE(enc, p) \ + ((p)[1] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ + : unicode_byte_type((p)[1], (p)[0])) +#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1) +#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c) +#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) +#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0]) + +#ifdef XML_MIN_SIZE + +static int PTRFASTCALL +little2_byteType(const ENCODING *enc, const char *p) +{ + return LITTLE2_BYTE_TYPE(enc, p); +} + +static int PTRFASTCALL +little2_byteToAscii(const ENCODING *enc, const char *p) +{ + return LITTLE2_BYTE_TO_ASCII(enc, p); +} + +static int PTRCALL +little2_charMatches(const ENCODING *enc, const char *p, int c) +{ + return LITTLE2_CHAR_MATCHES(enc, p, c); +} + +static int PTRFASTCALL +little2_isNameMin(const ENCODING *enc, const char *p) +{ + return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p); +} + +static int PTRFASTCALL +little2_isNmstrtMin(const ENCODING *enc, const char *p) +{ + return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p); +} + +#undef VTABLE +#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +#undef PREFIX +#define PREFIX(ident) little2_ ## ident +#define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p) +#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p) +#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c) +#define IS_NAME_CHAR(enc, p, n) 0 +#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) + +#define XML_TOK_IMPL_C +#include "xmltok_impl.c" +#undef XML_TOK_IMPL_C + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding little2_encoding_ns = { + { VTABLE, 2, 0, +#if BYTEORDER == 1234 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#endif + +static const struct normal_encoding little2_encoding = { + { VTABLE, 2, 0, +#if BYTEORDER == 1234 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#if BYTEORDER != 4321 + +#ifdef XML_NS + +static const struct normal_encoding internal_little2_encoding_ns = { + { VTABLE, 2, 0, 1 }, + { +#include "iasciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#endif + +static const struct normal_encoding internal_little2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#endif + + +#define BIG2_BYTE_TYPE(enc, p) \ + ((p)[0] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ + : unicode_byte_type((p)[0], (p)[1])) +#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1) +#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c) +#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) +#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1]) + +#ifdef XML_MIN_SIZE + +static int PTRFASTCALL +big2_byteType(const ENCODING *enc, const char *p) +{ + return BIG2_BYTE_TYPE(enc, p); +} + +static int PTRFASTCALL +big2_byteToAscii(const ENCODING *enc, const char *p) +{ + return BIG2_BYTE_TO_ASCII(enc, p); +} + +static int PTRCALL +big2_charMatches(const ENCODING *enc, const char *p, int c) +{ + return BIG2_CHAR_MATCHES(enc, p, c); +} + +static int PTRFASTCALL +big2_isNameMin(const ENCODING *enc, const char *p) +{ + return BIG2_IS_NAME_CHAR_MINBPC(enc, p); +} + +static int PTRFASTCALL +big2_isNmstrtMin(const ENCODING *enc, const char *p) +{ + return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p); +} + +#undef VTABLE +#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +#undef PREFIX +#define PREFIX(ident) big2_ ## ident +#define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p) +#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p) +#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c) +#define IS_NAME_CHAR(enc, p, n) 0 +#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) + +#define XML_TOK_IMPL_C +#include "xmltok_impl.c" +#undef XML_TOK_IMPL_C + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding big2_encoding_ns = { + { VTABLE, 2, 0, +#if BYTEORDER == 4321 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#endif + +static const struct normal_encoding big2_encoding = { + { VTABLE, 2, 0, +#if BYTEORDER == 4321 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#if BYTEORDER != 1234 + +#ifdef XML_NS + +static const struct normal_encoding internal_big2_encoding_ns = { + { VTABLE, 2, 0, 1 }, + { +#include "iasciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#endif + +static const struct normal_encoding internal_big2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#endif + +#undef PREFIX + +static int FASTCALL +streqci(const char *s1, const char *s2) +{ + for (;;) { + char c1 = *s1++; + char c2 = *s2++; + if (ASCII_a <= c1 && c1 <= ASCII_z) + c1 += ASCII_A - ASCII_a; + if (ASCII_a <= c2 && c2 <= ASCII_z) + c2 += ASCII_A - ASCII_a; + if (c1 != c2) + return 0; + if (!c1) + break; + } + return 1; +} + +static void PTRCALL +initUpdatePosition(const ENCODING *enc, const char *ptr, + const char *end, POSITION *pos) +{ + normal_updatePosition(&utf8_encoding.enc, ptr, end, pos); +} + +static int +toAscii(const ENCODING *enc, const char *ptr, const char *end) +{ + char buf[1]; + char *p = buf; + XmlUtf8Convert(enc, &ptr, end, &p, p + 1); + if (p == buf) + return -1; + else + return buf[0]; +} + +static int FASTCALL +isSpace(int c) +{ + switch (c) { + case 0x20: + case 0xD: + case 0xA: + case 0x9: + return 1; + } + return 0; +} + +/* Return 1 if there's just optional white space or there's an S + followed by name=val. +*/ +static int +parsePseudoAttribute(const ENCODING *enc, + const char *ptr, + const char *end, + const char **namePtr, + const char **nameEndPtr, + const char **valPtr, + const char **nextTokPtr) +{ + int c; + char open; + if (ptr == end) { + *namePtr = NULL; + return 1; + } + if (!isSpace(toAscii(enc, ptr, end))) { + *nextTokPtr = ptr; + return 0; + } + do { + ptr += enc->minBytesPerChar; + } while (isSpace(toAscii(enc, ptr, end))); + if (ptr == end) { + *namePtr = NULL; + return 1; + } + *namePtr = ptr; + for (;;) { + c = toAscii(enc, ptr, end); + if (c == -1) { + *nextTokPtr = ptr; + return 0; + } + if (c == ASCII_EQUALS) { + *nameEndPtr = ptr; + break; + } + if (isSpace(c)) { + *nameEndPtr = ptr; + do { + ptr += enc->minBytesPerChar; + } while (isSpace(c = toAscii(enc, ptr, end))); + if (c != ASCII_EQUALS) { + *nextTokPtr = ptr; + return 0; + } + break; + } + ptr += enc->minBytesPerChar; + } + if (ptr == *namePtr) { + *nextTokPtr = ptr; + return 0; + } + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + while (isSpace(c)) { + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + } + if (c != ASCII_QUOT && c != ASCII_APOS) { + *nextTokPtr = ptr; + return 0; + } + open = (char)c; + ptr += enc->minBytesPerChar; + *valPtr = ptr; + for (;; ptr += enc->minBytesPerChar) { + c = toAscii(enc, ptr, end); + if (c == open) + break; + if (!(ASCII_a <= c && c <= ASCII_z) + && !(ASCII_A <= c && c <= ASCII_Z) + && !(ASCII_0 <= c && c <= ASCII_9) + && c != ASCII_PERIOD + && c != ASCII_MINUS + && c != ASCII_UNDERSCORE) { + *nextTokPtr = ptr; + return 0; + } + } + *nextTokPtr = ptr + enc->minBytesPerChar; + return 1; +} + +static const char KW_version[] = { + ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0' +}; + +static const char KW_encoding[] = { + ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0' +}; + +static const char KW_standalone[] = { + ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o, + ASCII_n, ASCII_e, '\0' +}; + +static const char KW_yes[] = { + ASCII_y, ASCII_e, ASCII_s, '\0' +}; + +static const char KW_no[] = { + ASCII_n, ASCII_o, '\0' +}; + +static int +doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, + const char *, + const char *), + int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingName, + const ENCODING **encoding, + int *standalone) +{ + const char *val = NULL; + const char *name = NULL; + const char *nameEnd = NULL; + ptr += 5 * enc->minBytesPerChar; + end -= 2 * enc->minBytesPerChar; + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr) + || !name) { + *badPtr = ptr; + return 0; + } + if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) { + if (!isGeneralTextEntity) { + *badPtr = name; + return 0; + } + } + else { + if (versionPtr) + *versionPtr = val; + if (versionEndPtr) + *versionEndPtr = ptr; + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) { + if (isGeneralTextEntity) { + /* a TextDecl must have an EncodingDecl */ + *badPtr = ptr; + return 0; + } + return 1; + } + } + if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) { + int c = toAscii(enc, val, end); + if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) { + *badPtr = val; + return 0; + } + if (encodingName) + *encodingName = val; + if (encoding) + *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar); + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) + return 1; + } + if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone) + || isGeneralTextEntity) { + *badPtr = name; + return 0; + } + if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) { + if (standalone) + *standalone = 1; + } + else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) { + if (standalone) + *standalone = 0; + } + else { + *badPtr = val; + return 0; + } + while (isSpace(toAscii(enc, ptr, end))) + ptr += enc->minBytesPerChar; + if (ptr != end) { + *badPtr = ptr; + return 0; + } + return 1; +} + +static int FASTCALL +checkCharRefNumber(int result) +{ + switch (result >> 8) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return -1; + case 0: + if (latin1_encoding.type[result] == BT_NONXML) + return -1; + break; + case 0xFF: + if (result == 0xFFFE || result == 0xFFFF) + return -1; + break; + } + return result; +} + +int FASTCALL +XmlUtf8Encode(int c, char *buf) +{ + enum { + /* minN is minimum legal resulting value for N byte sequence */ + min2 = 0x80, + min3 = 0x800, + min4 = 0x10000 + }; + + if (c < 0) + return 0; + if (c < min2) { + buf[0] = (char)(c | UTF8_cval1); + return 1; + } + if (c < min3) { + buf[0] = (char)((c >> 6) | UTF8_cval2); + buf[1] = (char)((c & 0x3f) | 0x80); + return 2; + } + if (c < min4) { + buf[0] = (char)((c >> 12) | UTF8_cval3); + buf[1] = (char)(((c >> 6) & 0x3f) | 0x80); + buf[2] = (char)((c & 0x3f) | 0x80); + return 3; + } + if (c < 0x110000) { + buf[0] = (char)((c >> 18) | UTF8_cval4); + buf[1] = (char)(((c >> 12) & 0x3f) | 0x80); + buf[2] = (char)(((c >> 6) & 0x3f) | 0x80); + buf[3] = (char)((c & 0x3f) | 0x80); + return 4; + } + return 0; +} + +int FASTCALL +XmlUtf16Encode(int charNum, unsigned short *buf) +{ + if (charNum < 0) + return 0; + if (charNum < 0x10000) { + buf[0] = (unsigned short)charNum; + return 1; + } + if (charNum < 0x110000) { + charNum -= 0x10000; + buf[0] = (unsigned short)((charNum >> 10) + 0xD800); + buf[1] = (unsigned short)((charNum & 0x3FF) + 0xDC00); + return 2; + } + return 0; +} + +struct unknown_encoding { + struct normal_encoding normal; + CONVERTER convert; + void *userData; + unsigned short utf16[256]; + char utf8[256][4]; +}; + +#define AS_UNKNOWN_ENCODING(enc) ((const struct unknown_encoding *) (enc)) + +int +XmlSizeOfUnknownEncoding(void) +{ + return sizeof(struct unknown_encoding); +} + +static int PTRFASTCALL +unknown_isName(const ENCODING *enc, const char *p) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF); +} + +static int PTRFASTCALL +unknown_isNmstrt(const ENCODING *enc, const char *p) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF); +} + +static int PTRFASTCALL +unknown_isInvalid(const ENCODING *enc, const char *p) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + return (c & ~0xFFFF) || checkCharRefNumber(c) < 0; +} + +static void PTRCALL +unknown_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + char buf[XML_UTF8_ENCODE_MAX]; + for (;;) { + const char *utf8; + int n; + if (*fromP == fromLim) + break; + utf8 = uenc->utf8[(unsigned char)**fromP]; + n = *utf8++; + if (n == 0) { + int c = uenc->convert(uenc->userData, *fromP); + n = XmlUtf8Encode(c, buf); + if (n > toLim - *toP) + break; + utf8 = buf; + *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2)); + } + else { + if (n > toLim - *toP) + break; + (*fromP)++; + } + do { + *(*toP)++ = *utf8++; + } while (--n != 0); + } +} + +static void PTRCALL +unknown_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + while (*fromP != fromLim && *toP != toLim) { + unsigned short c = uenc->utf16[(unsigned char)**fromP]; + if (c == 0) { + c = (unsigned short) + uenc->convert(uenc->userData, *fromP); + *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2)); + } + else + (*fromP)++; + *(*toP)++ = c; + } +} + +ENCODING * +XmlInitUnknownEncoding(void *mem, + int *table, + CONVERTER convert, + void *userData) +{ + int i; + struct unknown_encoding *e = (struct unknown_encoding *)mem; + for (i = 0; i < (int)sizeof(struct normal_encoding); i++) + ((char *)mem)[i] = ((char *)&latin1_encoding)[i]; + for (i = 0; i < 128; i++) + if (latin1_encoding.type[i] != BT_OTHER + && latin1_encoding.type[i] != BT_NONXML + && table[i] != i) + return 0; + for (i = 0; i < 256; i++) { + int c = table[i]; + if (c == -1) { + e->normal.type[i] = BT_MALFORM; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else if (c < 0) { + if (c < -4) + return 0; + e->normal.type[i] = (unsigned char)(BT_LEAD2 - (c + 2)); + e->utf8[i][0] = 0; + e->utf16[i] = 0; + } + else if (c < 0x80) { + if (latin1_encoding.type[c] != BT_OTHER + && latin1_encoding.type[c] != BT_NONXML + && c != i) + return 0; + e->normal.type[i] = latin1_encoding.type[c]; + e->utf8[i][0] = 1; + e->utf8[i][1] = (char)c; + e->utf16[i] = (unsigned short)(c == 0 ? 0xFFFF : c); + } + else if (checkCharRefNumber(c) < 0) { + e->normal.type[i] = BT_NONXML; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else { + if (c > 0xFFFF) + return 0; + if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NMSTRT; + else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NAME; + else + e->normal.type[i] = BT_OTHER; + e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1); + e->utf16[i] = (unsigned short)c; + } + } + e->userData = userData; + e->convert = convert; + if (convert) { + e->normal.isName2 = unknown_isName; + e->normal.isName3 = unknown_isName; + e->normal.isName4 = unknown_isName; + e->normal.isNmstrt2 = unknown_isNmstrt; + e->normal.isNmstrt3 = unknown_isNmstrt; + e->normal.isNmstrt4 = unknown_isNmstrt; + e->normal.isInvalid2 = unknown_isInvalid; + e->normal.isInvalid3 = unknown_isInvalid; + e->normal.isInvalid4 = unknown_isInvalid; + } + e->normal.enc.utf8Convert = unknown_toUtf8; + e->normal.enc.utf16Convert = unknown_toUtf16; + return &(e->normal.enc); +} + +/* If this enumeration is changed, getEncodingIndex and encodings +must also be changed. */ +enum { + UNKNOWN_ENC = -1, + ISO_8859_1_ENC = 0, + US_ASCII_ENC, + UTF_8_ENC, + UTF_16_ENC, + UTF_16BE_ENC, + UTF_16LE_ENC, + /* must match encodingNames up to here */ + NO_ENC +}; + +static const char KW_ISO_8859_1[] = { + ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9, + ASCII_MINUS, ASCII_1, '\0' +}; +static const char KW_US_ASCII[] = { + ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I, + '\0' +}; +static const char KW_UTF_8[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0' +}; +static const char KW_UTF_16[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0' +}; +static const char KW_UTF_16BE[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E, + '\0' +}; +static const char KW_UTF_16LE[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E, + '\0' +}; + +static int FASTCALL +getEncodingIndex(const char *name) +{ + static const char * const encodingNames[] = { + KW_ISO_8859_1, + KW_US_ASCII, + KW_UTF_8, + KW_UTF_16, + KW_UTF_16BE, + KW_UTF_16LE, + }; + int i; + if (name == NULL) + return NO_ENC; + for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++) + if (streqci(name, encodingNames[i])) + return i; + return UNKNOWN_ENC; +} + +/* For binary compatibility, we store the index of the encoding + specified at initialization in the isUtf16 member. +*/ + +#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16) +#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i) + +/* This is what detects the encoding. encodingTable maps from + encoding indices to encodings; INIT_ENC_INDEX(enc) is the index of + the external (protocol) specified encoding; state is + XML_CONTENT_STATE if we're parsing an external text entity, and + XML_PROLOG_STATE otherwise. +*/ + + +static int +initScan(const ENCODING * const *encodingTable, + const INIT_ENCODING *enc, + int state, + const char *ptr, + const char *end, + const char **nextTokPtr) +{ + const ENCODING **encPtr; + + if (ptr == end) + return XML_TOK_NONE; + encPtr = enc->encPtr; + if (ptr + 1 == end) { + /* only a single byte available for auto-detection */ +#ifndef XML_DTD /* FIXME */ + /* a well-formed document entity must have more than one byte */ + if (state != XML_CONTENT_STATE) + return XML_TOK_PARTIAL; +#endif + /* so we're parsing an external text entity... */ + /* if UTF-16 was externally specified, then we need at least 2 bytes */ + switch (INIT_ENC_INDEX(enc)) { + case UTF_16_ENC: + case UTF_16LE_ENC: + case UTF_16BE_ENC: + return XML_TOK_PARTIAL; + } + switch ((unsigned char)*ptr) { + case 0xFE: + case 0xFF: + case 0xEF: /* possibly first byte of UTF-8 BOM */ + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + /* fall through */ + case 0x00: + case 0x3C: + return XML_TOK_PARTIAL; + } + } + else { + switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) { + case 0xFEFF: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XML_TOK_BOM; + /* 00 3C is handled in the default case */ + case 0x3C00: + if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC + || INIT_ENC_INDEX(enc) == UTF_16_ENC) + && state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + case 0xFFFE: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XML_TOK_BOM; + case 0xEFBB: + /* Maybe a UTF-8 BOM (EF BB BF) */ + /* If there's an explicitly specified (external) encoding + of ISO-8859-1 or some flavour of UTF-16 + and this is an external text entity, + don't look for the BOM, + because it might be a legal data. + */ + if (state == XML_CONTENT_STATE) { + int e = INIT_ENC_INDEX(enc); + if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC + || e == UTF_16LE_ENC || e == UTF_16_ENC) + break; + } + if (ptr + 2 == end) + return XML_TOK_PARTIAL; + if ((unsigned char)ptr[2] == 0xBF) { + *nextTokPtr = ptr + 3; + *encPtr = encodingTable[UTF_8_ENC]; + return XML_TOK_BOM; + } + break; + default: + if (ptr[0] == '\0') { + /* 0 isn't a legal data character. Furthermore a document + entity can only start with ASCII characters. So the only + way this can fail to be big-endian UTF-16 if it it's an + external parsed general entity that's labelled as + UTF-16LE. + */ + if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC) + break; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } + else if (ptr[1] == '\0') { + /* We could recover here in the case: + - parsing an external entity + - second byte is 0 + - no externally specified encoding + - no encoding declaration + by assuming UTF-16LE. But we don't, because this would mean when + presented just with a single byte, we couldn't reliably determine + whether we needed further bytes. + */ + if (state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } + break; + } + } + *encPtr = encodingTable[INIT_ENC_INDEX(enc)]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); +} + + +#define NS(x) x +#define ns(x) x +#define XML_TOK_NS_C +#include "xmltok_ns.c" +#undef XML_TOK_NS_C +#undef NS +#undef ns + +#ifdef XML_NS + +#define NS(x) x ## NS +#define ns(x) x ## _ns + +#define XML_TOK_NS_C +#include "xmltok_ns.c" +#undef XML_TOK_NS_C + +#undef NS +#undef ns + +ENCODING * +XmlInitUnknownEncodingNS(void *mem, + int *table, + CONVERTER convert, + void *userData) +{ + ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData); + if (enc) + ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON; + return enc; +} + +#endif /* XML_NS */ diff -Nru simgear-2.10.0/3rdparty/expat/xmltok.h simgear-3.0.0/3rdparty/expat/xmltok.h --- simgear-2.10.0/3rdparty/expat/xmltok.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/xmltok.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,316 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef XmlTok_INCLUDED +#define XmlTok_INCLUDED 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* The following token may be returned by XmlContentTok */ +#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be + start of illegal ]]> sequence */ +/* The following tokens may be returned by both XmlPrologTok and + XmlContentTok. +*/ +#define XML_TOK_NONE -4 /* The string to be scanned is empty */ +#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan; + might be part of CRLF sequence */ +#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ +#define XML_TOK_PARTIAL -1 /* only part of a token */ +#define XML_TOK_INVALID 0 + +/* The following tokens are returned by XmlContentTok; some are also + returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok. +*/ +#define XML_TOK_START_TAG_WITH_ATTS 1 +#define XML_TOK_START_TAG_NO_ATTS 2 +#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag */ +#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 +#define XML_TOK_END_TAG 5 +#define XML_TOK_DATA_CHARS 6 +#define XML_TOK_DATA_NEWLINE 7 +#define XML_TOK_CDATA_SECT_OPEN 8 +#define XML_TOK_ENTITY_REF 9 +#define XML_TOK_CHAR_REF 10 /* numeric character reference */ + +/* The following tokens may be returned by both XmlPrologTok and + XmlContentTok. +*/ +#define XML_TOK_PI 11 /* processing instruction */ +#define XML_TOK_XML_DECL 12 /* XML decl or text decl */ +#define XML_TOK_COMMENT 13 +#define XML_TOK_BOM 14 /* Byte order mark */ + +/* The following tokens are returned only by XmlPrologTok */ +#define XML_TOK_PROLOG_S 15 +#define XML_TOK_DECL_OPEN 16 /* */ +#define XML_TOK_NAME 18 +#define XML_TOK_NMTOKEN 19 +#define XML_TOK_POUND_NAME 20 /* #name */ +#define XML_TOK_OR 21 /* | */ +#define XML_TOK_PERCENT 22 +#define XML_TOK_OPEN_PAREN 23 +#define XML_TOK_CLOSE_PAREN 24 +#define XML_TOK_OPEN_BRACKET 25 +#define XML_TOK_CLOSE_BRACKET 26 +#define XML_TOK_LITERAL 27 +#define XML_TOK_PARAM_ENTITY_REF 28 +#define XML_TOK_INSTANCE_START 29 + +/* The following occur only in element type declarations */ +#define XML_TOK_NAME_QUESTION 30 /* name? */ +#define XML_TOK_NAME_ASTERISK 31 /* name* */ +#define XML_TOK_NAME_PLUS 32 /* name+ */ +#define XML_TOK_COND_SECT_OPEN 33 /* */ +#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ +#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ +#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ +#define XML_TOK_COMMA 38 + +/* The following token is returned only by XmlAttributeValueTok */ +#define XML_TOK_ATTRIBUTE_VALUE_S 39 + +/* The following token is returned only by XmlCdataSectionTok */ +#define XML_TOK_CDATA_SECT_CLOSE 40 + +/* With namespace processing this is returned by XmlPrologTok for a + name with a colon. +*/ +#define XML_TOK_PREFIXED_NAME 41 + +#ifdef XML_DTD +#define XML_TOK_IGNORE_SECT 42 +#endif /* XML_DTD */ + +#ifdef XML_DTD +#define XML_N_STATES 4 +#else /* not XML_DTD */ +#define XML_N_STATES 3 +#endif /* not XML_DTD */ + +#define XML_PROLOG_STATE 0 +#define XML_CONTENT_STATE 1 +#define XML_CDATA_SECTION_STATE 2 +#ifdef XML_DTD +#define XML_IGNORE_SECTION_STATE 3 +#endif /* XML_DTD */ + +#define XML_N_LITERAL_TYPES 2 +#define XML_ATTRIBUTE_VALUE_LITERAL 0 +#define XML_ENTITY_VALUE_LITERAL 1 + +/* The size of the buffer passed to XmlUtf8Encode must be at least this. */ +#define XML_UTF8_ENCODE_MAX 4 +/* The size of the buffer passed to XmlUtf16Encode must be at least this. */ +#define XML_UTF16_ENCODE_MAX 2 + +typedef struct position { + /* first line and first column are 0 not 1 */ + XML_Size lineNumber; + XML_Size columnNumber; +} POSITION; + +typedef struct { + const char *name; + const char *valuePtr; + const char *valueEnd; + char normalized; +} ATTRIBUTE; + +struct encoding; +typedef struct encoding ENCODING; + +typedef int (PTRCALL *SCANNER)(const ENCODING *, + const char *, + const char *, + const char **); + +struct encoding { + SCANNER scanners[XML_N_STATES]; + SCANNER literalScanners[XML_N_LITERAL_TYPES]; + int (PTRCALL *sameName)(const ENCODING *, + const char *, + const char *); + int (PTRCALL *nameMatchesAscii)(const ENCODING *, + const char *, + const char *, + const char *); + int (PTRFASTCALL *nameLength)(const ENCODING *, const char *); + const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *); + int (PTRCALL *getAtts)(const ENCODING *enc, + const char *ptr, + int attsMax, + ATTRIBUTE *atts); + int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr); + int (PTRCALL *predefinedEntityName)(const ENCODING *, + const char *, + const char *); + void (PTRCALL *updatePosition)(const ENCODING *, + const char *ptr, + const char *end, + POSITION *); + int (PTRCALL *isPublicId)(const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr); + void (PTRCALL *utf8Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + char **toP, + const char *toLim); + void (PTRCALL *utf16Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + unsigned short **toP, + const unsigned short *toLim); + int minBytesPerChar; + char isUtf8; + char isUtf16; +}; + +/* Scan the string starting at ptr until the end of the next complete + token, but do not scan past eptr. Return an integer giving the + type of token. + + Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set. + + Return XML_TOK_PARTIAL when the string does not contain a complete + token; nextTokPtr will not be set. + + Return XML_TOK_INVALID when the string does not start a valid + token; nextTokPtr will be set to point to the character which made + the token invalid. + + Otherwise the string starts with a valid token; nextTokPtr will be + set to point to the character following the end of that token. + + Each data character counts as a single token, but adjacent data + characters may be returned together. Similarly for characters in + the prolog outside literals, comments and processing instructions. +*/ + + +#define XmlTok(enc, state, ptr, end, nextTokPtr) \ + (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) + +#define XmlPrologTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) + +#define XmlContentTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) + +#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) + +#ifdef XML_DTD + +#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr) + +#endif /* XML_DTD */ + +/* This is used for performing a 2nd-level tokenization on the content + of a literal that has already been returned by XmlTok. +*/ +#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ + (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) + +#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2)) + +#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \ + (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2)) + +#define XmlNameLength(enc, ptr) \ + (((enc)->nameLength)(enc, ptr)) + +#define XmlSkipS(enc, ptr) \ + (((enc)->skipS)(enc, ptr)) + +#define XmlGetAttributes(enc, ptr, attsMax, atts) \ + (((enc)->getAtts)(enc, ptr, attsMax, atts)) + +#define XmlCharRefNumber(enc, ptr) \ + (((enc)->charRefNumber)(enc, ptr)) + +#define XmlPredefinedEntityName(enc, ptr, end) \ + (((enc)->predefinedEntityName)(enc, ptr, end)) + +#define XmlUpdatePosition(enc, ptr, end, pos) \ + (((enc)->updatePosition)(enc, ptr, end, pos)) + +#define XmlIsPublicId(enc, ptr, end, badPtr) \ + (((enc)->isPublicId)(enc, ptr, end, badPtr)) + +#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) + +#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) + +typedef struct { + ENCODING initEnc; + const ENCODING **encPtr; +} INIT_ENCODING; + +int XmlParseXmlDecl(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingNamePtr, + const ENCODING **namedEncodingPtr, + int *standalonePtr); + +int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name); +const ENCODING *XmlGetUtf8InternalEncoding(void); +const ENCODING *XmlGetUtf16InternalEncoding(void); +int FASTCALL XmlUtf8Encode(int charNumber, char *buf); +int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf); +int XmlSizeOfUnknownEncoding(void); + + +typedef int (XMLCALL *CONVERTER) (void *userData, const char *p); + +ENCODING * +XmlInitUnknownEncoding(void *mem, + int *table, + CONVERTER convert, + void *userData); + +int XmlParseXmlDeclNS(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingNamePtr, + const ENCODING **namedEncodingPtr, + int *standalonePtr); + +int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name); +const ENCODING *XmlGetUtf8InternalEncodingNS(void); +const ENCODING *XmlGetUtf16InternalEncodingNS(void); +ENCODING * +XmlInitUnknownEncodingNS(void *mem, + int *table, + CONVERTER convert, + void *userData); +#ifdef __cplusplus +} +#endif + +#endif /* not XmlTok_INCLUDED */ diff -Nru simgear-2.10.0/3rdparty/expat/xmltok_impl.c simgear-3.0.0/3rdparty/expat/xmltok_impl.c --- simgear-2.10.0/3rdparty/expat/xmltok_impl.c 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/xmltok_impl.c 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,1783 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +/* This file is included! */ +#ifdef XML_TOK_IMPL_C + +#ifndef IS_INVALID_CHAR +#define IS_INVALID_CHAR(enc, ptr, n) (0) +#endif + +#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_INVALID_CHAR(enc, ptr, n)) { \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define INVALID_CASES(ptr, nextTokPtr) \ + INVALID_LEAD_CASE(2, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(3, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(4, ptr, nextTokPtr) \ + case BT_NONXML: \ + case BT_MALFORM: \ + case BT_TRAIL: \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; + +#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NAME_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + case BT_DIGIT: \ + case BT_NAME: \ + case BT_MINUS: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr) + +#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr) + +#ifndef PREFIX +#define PREFIX(ident) ident +#endif + +/* ptr points to character following " */ + switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) { + case BT_S: case BT_CR: case BT_LF: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + /* fall through */ + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DECL_OPEN; + case BT_NMSTRT: + case BT_HEX: + ptr += MINBPC(enc); + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr, + const char *end, int *tokPtr) +{ + int upper = 0; + *tokPtr = XML_TOK_PI; + if (end - ptr != MINBPC(enc)*3) + return 1; + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_x: + break; + case ASCII_X: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_m: + break; + case ASCII_M: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + break; + case ASCII_L: + upper = 1; + break; + default: + return 1; + } + if (upper) + return 0; + *tokPtr = XML_TOK_XML_DECL; + return 1; +} + +/* ptr points to character following " 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CDATA_SECT_CLOSE; + case BT_CR: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + case BT_RSQB: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following " 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_LT: + return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_AMP: + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_CR: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_RSQB: + if (ptr + MINBPC(enc) != end) { + if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) { + ptr += MINBPC(enc); + break; + } + if (ptr + 2*MINBPC(enc) != end) { + if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) { + ptr += MINBPC(enc); + break; + } + *nextTokPtr = ptr + 2*MINBPC(enc); + return XML_TOK_INVALID; + } + } + /* fall through */ + case BT_AMP: + case BT_LT: + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following "%" */ + +static int PTRCALL +PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_LF: case BT_CR: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_PERCENT; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_PARAM_ENTITY_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_CR: case BT_LF: case BT_S: + case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR: + *nextTokPtr = ptr; + return XML_TOK_POUND_NAME; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -XML_TOK_POUND_NAME; +} + +static int PTRCALL +PREFIX(scanLit)(int open, const ENCODING *enc, + const char *ptr, const char *end, + const char **nextTokPtr) +{ + while (ptr != end) { + int t = BYTE_TYPE(enc, ptr); + switch (t) { + INVALID_CASES(ptr, nextTokPtr) + case BT_QUOT: + case BT_APOS: + ptr += MINBPC(enc); + if (t != open) + break; + if (ptr == end) + return -XML_TOK_LITERAL; + *nextTokPtr = ptr; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_CR: case BT_LF: + case BT_GT: case BT_PERCNT: case BT_LSQB: + return XML_TOK_LITERAL; + default: + return XML_TOK_INVALID; + } + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + int tok; + if (ptr == end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_QUOT: + return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_APOS: + return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_LT: + { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_EXCL: + return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_QUEST: + return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_NMSTRT: + case BT_HEX: + case BT_NONASCII: + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + *nextTokPtr = ptr - MINBPC(enc); + return XML_TOK_INSTANCE_START; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + case BT_CR: + if (ptr + MINBPC(enc) == end) { + *nextTokPtr = end; + /* indicate that this might be part of a CR/LF pair */ + return -XML_TOK_PROLOG_S; + } + /* fall through */ + case BT_S: case BT_LF: + for (;;) { + ptr += MINBPC(enc); + if (ptr == end) + break; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_LF: + break; + case BT_CR: + /* don't split CR/LF pair */ + if (ptr + MINBPC(enc) != end) + break; + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + } + } + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + case BT_PERCNT: + return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_COMMA: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_COMMA; + case BT_LSQB: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_BRACKET; + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return -XML_TOK_CLOSE_BRACKET; + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + if (ptr + MINBPC(enc) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) { + *nextTokPtr = ptr + 2*MINBPC(enc); + return XML_TOK_COND_SECT_CLOSE; + } + } + *nextTokPtr = ptr; + return XML_TOK_CLOSE_BRACKET; + case BT_LPAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_PAREN; + case BT_RPAR: + ptr += MINBPC(enc); + if (ptr == end) + return -XML_TOK_CLOSE_PAREN; + switch (BYTE_TYPE(enc, ptr)) { + case BT_AST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_ASTERISK; + case BT_QUEST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_QUESTION; + case BT_PLUS: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_PLUS; + case BT_CR: case BT_LF: case BT_S: + case BT_GT: case BT_COMMA: case BT_VERBAR: + case BT_RPAR: + *nextTokPtr = ptr; + return XML_TOK_CLOSE_PAREN; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_VERBAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OR; + case BT_GT: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DECL_CLOSE; + case BT_NUM: + return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr); +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_NMSTRT_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NAME; \ + break; \ + } \ + if (IS_NAME_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NMTOKEN; \ + break; \ + } \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NMSTRT: + case BT_HEX: + tok = XML_TOK_NAME; + ptr += MINBPC(enc); + break; + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: +#ifdef XML_NS + case BT_COLON: +#endif + tok = XML_TOK_NMTOKEN; + ptr += MINBPC(enc); + break; + case BT_NONASCII: + if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NAME; + break; + } + if (IS_NAME_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NMTOKEN; + break; + } + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_GT: case BT_RPAR: case BT_COMMA: + case BT_VERBAR: case BT_LSQB: case BT_PERCNT: + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return tok; +#ifdef XML_NS + case BT_COLON: + ptr += MINBPC(enc); + switch (tok) { + case XML_TOK_NAME: + if (ptr == end) + return XML_TOK_PARTIAL; + tok = XML_TOK_PREFIXED_NAME; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + default: + tok = XML_TOK_NMTOKEN; + break; + } + break; + case XML_TOK_PREFIXED_NAME: + tok = XML_TOK_NMTOKEN; + break; + } + break; +#endif + case BT_PLUS: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_PLUS; + case BT_AST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_ASTERISK; + case BT_QUEST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_QUESTION; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -tok; +} + +static int PTRCALL +PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LT: + /* this is for inside entity references */ + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_S: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_ATTRIBUTE_VALUE_S; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +static int PTRCALL +PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_PERCNT: + if (ptr == start) { + int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc), + end, nextTokPtr); + return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +#ifdef XML_DTD + +static int PTRCALL +PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + int level = 0; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + end = ptr + n; + } + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + INVALID_CASES(ptr, nextTokPtr) + case BT_LT: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) { + ++level; + ptr += MINBPC(enc); + } + } + break; + case BT_RSQB: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr += MINBPC(enc); + if (level == 0) { + *nextTokPtr = ptr; + return XML_TOK_IGNORE_SECT; + } + --level; + } + } + break; + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +#endif /* XML_DTD */ + +static int PTRCALL +PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, + const char **badPtr) +{ + ptr += MINBPC(enc); + end -= MINBPC(enc); + for (; ptr != end; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + case BT_HEX: + case BT_MINUS: + case BT_APOS: + case BT_LPAR: + case BT_RPAR: + case BT_PLUS: + case BT_COMMA: + case BT_SOL: + case BT_EQUALS: + case BT_QUEST: + case BT_CR: + case BT_LF: + case BT_SEMI: + case BT_EXCL: + case BT_AST: + case BT_PERCNT: + case BT_NUM: +#ifdef XML_NS + case BT_COLON: +#endif + break; + case BT_S: + if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) { + *badPtr = ptr; + return 0; + } + break; + case BT_NAME: + case BT_NMSTRT: + if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f)) + break; + default: + switch (BYTE_TO_ASCII(enc, ptr)) { + case 0x24: /* $ */ + case 0x40: /* @ */ + break; + default: + *badPtr = ptr; + return 0; + } + break; + } + } + return 1; +} + +/* This must only be called for a well-formed start-tag or empty + element tag. Returns the number of attributes. Pointers to the + first attsMax attributes are stored in atts. +*/ + +static int PTRCALL +PREFIX(getAtts)(const ENCODING *enc, const char *ptr, + int attsMax, ATTRIBUTE *atts) +{ + enum { other, inName, inValue } state = inName; + int nAtts = 0; + int open = 0; /* defined when state == inValue; + initialization just to shut up compilers */ + + for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { +#define START_NAME \ + if (state == other) { \ + if (nAtts < attsMax) { \ + atts[nAtts].name = ptr; \ + atts[nAtts].normalized = 1; \ + } \ + state = inName; \ + } +#define LEAD_CASE(n) \ + case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: + case BT_HEX: + START_NAME + break; +#undef START_NAME + case BT_QUOT: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_QUOT; + } + else if (open == BT_QUOT) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_APOS: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_APOS; + } + else if (open == BT_APOS) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_AMP: + if (nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_S: + if (state == inName) + state = other; + else if (state == inValue + && nAtts < attsMax + && atts[nAtts].normalized + && (ptr == atts[nAtts].valuePtr + || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE + || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE + || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open)) + atts[nAtts].normalized = 0; + break; + case BT_CR: case BT_LF: + /* This case ensures that the first attribute name is counted + Apart from that we could just change state on the quote. */ + if (state == inName) + state = other; + else if (state == inValue && nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_GT: + case BT_SOL: + if (state != inValue) + return nAtts; + break; + default: + break; + } + } + /* not reached */ +} + +static int PTRFASTCALL +PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr) +{ + int result = 0; + /* skip &# */ + ptr += 2*MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_x)) { + for (ptr += MINBPC(enc); + !CHAR_MATCHES(enc, ptr, ASCII_SEMI); + ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + switch (c) { + case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4: + case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9: + result <<= 4; + result |= (c - ASCII_0); + break; + case ASCII_A: case ASCII_B: case ASCII_C: + case ASCII_D: case ASCII_E: case ASCII_F: + result <<= 4; + result += 10 + (c - ASCII_A); + break; + case ASCII_a: case ASCII_b: case ASCII_c: + case ASCII_d: case ASCII_e: case ASCII_f: + result <<= 4; + result += 10 + (c - ASCII_a); + break; + } + if (result >= 0x110000) + return -1; + } + } + else { + for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + result *= 10; + result += (c - ASCII_0); + if (result >= 0x110000) + return -1; + } + } + return checkCharRefNumber(result); +} + +static int PTRCALL +PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr, + const char *end) +{ + switch ((end - ptr)/MINBPC(enc)) { + case 2: + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) { + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + return ASCII_LT; + case ASCII_g: + return ASCII_GT; + } + } + break; + case 3: + if (CHAR_MATCHES(enc, ptr, ASCII_a)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_m)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) + return ASCII_AMP; + } + } + break; + case 4: + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_q: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_u)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_t)) + return ASCII_QUOT; + } + } + break; + case ASCII_a: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_s)) + return ASCII_APOS; + } + } + break; + } + } + return 0; +} + +static int PTRCALL +PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr1)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (*ptr1++ != *ptr2++) \ + return 0; + LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2) +#undef LEAD_CASE + /* fall through */ + if (*ptr1++ != *ptr2++) + return 0; + break; + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 1) { + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 2) { + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 3) { + if (*ptr2++ != *ptr1++) + return 0; + } + } + } + break; + default: + if (MINBPC(enc) == 1 && *ptr1 == *ptr2) + return 1; + switch (BYTE_TYPE(enc, ptr2)) { + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + return 0; + default: + return 1; + } + } + } + /* not reached */ +} + +static int PTRCALL +PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1, + const char *end1, const char *ptr2) +{ + for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) { + if (ptr1 == end1) + return 0; + if (!CHAR_MATCHES(enc, ptr1, *ptr2)) + return 0; + } + return ptr1 == end1; +} + +static int PTRFASTCALL +PREFIX(nameLength)(const ENCODING *enc, const char *ptr) +{ + const char *start = ptr; + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + ptr += MINBPC(enc); + break; + default: + return (int)(ptr - start); + } + } +} + +static const char * PTRFASTCALL +PREFIX(skipS)(const ENCODING *enc, const char *ptr) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_LF: + case BT_CR: + case BT_S: + ptr += MINBPC(enc); + break; + default: + return ptr; + } + } +} + +static void PTRCALL +PREFIX(updatePosition)(const ENCODING *enc, + const char *ptr, + const char *end, + POSITION *pos) +{ + while (ptr < end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_LF: + pos->columnNumber = (XML_Size)-1; + pos->lineNumber++; + ptr += MINBPC(enc); + break; + case BT_CR: + pos->lineNumber++; + ptr += MINBPC(enc); + if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + pos->columnNumber = (XML_Size)-1; + break; + default: + ptr += MINBPC(enc); + break; + } + pos->columnNumber++; + } +} + +#undef DO_LEAD_CASE +#undef MULTIBYTE_CASES +#undef INVALID_CASES +#undef CHECK_NAME_CASE +#undef CHECK_NAME_CASES +#undef CHECK_NMSTRT_CASE +#undef CHECK_NMSTRT_CASES + +#endif /* XML_TOK_IMPL_C */ diff -Nru simgear-2.10.0/3rdparty/expat/xmltok_impl.h simgear-3.0.0/3rdparty/expat/xmltok_impl.h --- simgear-2.10.0/3rdparty/expat/xmltok_impl.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/xmltok_impl.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,71 @@ +/* +The contents of this file are subject to the Mozilla Public License +Version 1.1 (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.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +License for the specific language governing rights and limitations +under the License. + +The Original Code is expat. + +The Initial Developer of the Original Code is James Clark. +Portions created by James Clark are Copyright (C) 1998, 1999 +James Clark. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms +of the GNU General Public License (the "GPL"), in which case the +provisions of the GPL are applicable instead of those above. If you +wish to allow use of your version of this file only under the terms of +the GPL and not to allow others to use your version of this file under +the MPL, indicate your decision by deleting the provisions above and +replace them with the notice and other provisions required by the +GPL. If you do not delete the provisions above, a recipient may use +your version of this file under either the MPL or the GPL. +*/ + +enum { + BT_NONXML, + BT_MALFORM, + BT_LT, + BT_AMP, + BT_RSQB, + BT_LEAD2, + BT_LEAD3, + BT_LEAD4, + BT_TRAIL, + BT_CR, + BT_LF, + BT_GT, + BT_QUOT, + BT_APOS, + BT_EQUALS, + BT_QUEST, + BT_EXCL, + BT_SOL, + BT_SEMI, + BT_NUM, + BT_LSQB, + BT_S, + BT_NMSTRT, + BT_COLON, + BT_HEX, + BT_DIGIT, + BT_NAME, + BT_MINUS, + BT_OTHER, /* known not to be a name or name start character */ + BT_NONASCII, /* might be a name or name start character */ + BT_PERCNT, + BT_LPAR, + BT_RPAR, + BT_AST, + BT_PLUS, + BT_COMMA, + BT_VERBAR +}; + +#include diff -Nru simgear-2.10.0/3rdparty/expat/xmltok_ns.c simgear-3.0.0/3rdparty/expat/xmltok_ns.c --- simgear-2.10.0/3rdparty/expat/xmltok_ns.c 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/3rdparty/expat/xmltok_ns.c 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,115 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +/* This file is included! */ +#ifdef XML_TOK_NS_C + +const ENCODING * +NS(XmlGetUtf8InternalEncoding)(void) +{ + return &ns(internal_utf8_encoding).enc; +} + +const ENCODING * +NS(XmlGetUtf16InternalEncoding)(void) +{ +#if BYTEORDER == 1234 + return &ns(internal_little2_encoding).enc; +#elif BYTEORDER == 4321 + return &ns(internal_big2_encoding).enc; +#else + const short n = 1; + return (*(const char *)&n + ? &ns(internal_little2_encoding).enc + : &ns(internal_big2_encoding).enc); +#endif +} + +static const ENCODING * const NS(encodings)[] = { + &ns(latin1_encoding).enc, + &ns(ascii_encoding).enc, + &ns(utf8_encoding).enc, + &ns(big2_encoding).enc, + &ns(big2_encoding).enc, + &ns(little2_encoding).enc, + &ns(utf8_encoding).enc /* NO_ENC */ +}; + +static int PTRCALL +NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(NS(encodings), (const INIT_ENCODING *)enc, + XML_PROLOG_STATE, ptr, end, nextTokPtr); +} + +static int PTRCALL +NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(NS(encodings), (const INIT_ENCODING *)enc, + XML_CONTENT_STATE, ptr, end, nextTokPtr); +} + +int +NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr, + const char *name) +{ + int i = getEncodingIndex(name); + if (i == UNKNOWN_ENC) + return 0; + SET_INIT_ENC_INDEX(p, i); + p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog); + p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent); + p->initEnc.updatePosition = initUpdatePosition; + p->encPtr = encPtr; + *encPtr = &(p->initEnc); + return 1; +} + +static const ENCODING * +NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) +{ +#define ENCODING_MAX 128 + char buf[ENCODING_MAX]; + char *p = buf; + int i; + XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); + if (ptr != end) + return 0; + *p = 0; + if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2) + return enc; + i = getEncodingIndex(buf); + if (i == UNKNOWN_ENC) + return 0; + return NS(encodings)[i]; +} + +int +NS(XmlParseXmlDecl)(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingName, + const ENCODING **encoding, + int *standalone) +{ + return doParseXmlDecl(NS(findEncoding), + isGeneralTextEntity, + enc, + ptr, + end, + badPtr, + versionPtr, + versionEndPtr, + encodingName, + encoding, + standalone); +} + +#endif /* XML_TOK_NS_C */ diff -Nru simgear-2.10.0/CMakeLists.txt simgear-3.0.0/CMakeLists.txt --- simgear-2.10.0/CMakeLists.txt 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -2,7 +2,7 @@ include (CheckFunctionExists) include (CheckIncludeFile) include (CheckCXXSourceCompiles) - +include (CheckCXXCompilerFlag) project(SimGear) @@ -10,6 +10,8 @@ file(READ version versionFile) string(STRIP ${versionFile} SIMGEAR_VERSION) +set(FIND_LIBRARY_USE_LIB64_PATHS ON) + # use simgear version also as the SO version (if building SOs) SET(SIMGEAR_SOVERSION ${SIMGEAR_VERSION}) @@ -85,13 +87,6 @@ message(STATUS "additional library directories: ${ADDITIONAL_LIBRARY_PATHS}") endif() -if(NOT MSVC) - # TBD: are these really necessary? Aren't they considered by cmake automatically? - list(APPEND ADDITIONAL_LIBRARY_PATHS - /opt/local - /usr/local - /usr) -endif() ##################################################################################### if (NOT MSVC) @@ -106,13 +101,13 @@ option(SIMGEAR_HEADLESS "Set to ON to build SimGear without GUI/graphics support" OFF) option(JPEG_FACTORY "Enable JPEG-factory support" OFF) -option(ENABLE_LIBSVN "Set to ON to build SimGear with libsvnclient support" ON) option(ENABLE_RTI "Set to ON to build SimGear with RTI support" OFF) option(ENABLE_TESTS "Set to OFF to disable building SimGear's test applications" ON) option(ENABLE_SOUND "Set to OFF to disable building SimGear's sound support" ON) +option(ENABLE_PKGUTIL "Set to ON to build the sg_pkgutil application (default)" ON) if (MSVC) - GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_SOURCE_DIR} PATH) + GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH) if (CMAKE_CL_64) SET(TEST_3RDPARTY_DIR "${PARENT_DIR}/3rdparty.x64") else (CMAKE_CL_64) @@ -165,6 +160,10 @@ set (OPENAL_LIBRARY_DIR ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib) endif (MSVC AND MSVC_3RDPARTY_ROOT) +if(APPLE) + find_library(CORE_SERVICES_LIBRARY CoreServices) +endif() + find_package(Boost REQUIRED) set (BOOST_CXX_FLAGS "-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION -DBOOST_BIMAP_DISABLE_SERIALIZATION") @@ -191,23 +190,6 @@ message(STATUS "JPEG-factory: DISABLED") endif(JPEG_FACTORY) -if(ENABLE_LIBSVN) - find_package(SvnClient) - - if(LIBSVN_FOUND) - message(STATUS "Subversion client support: ENABLED") - set(HAVE_SVN_CLIENT_H 1) - set(HAVE_LIBSVN_CLIENT_1 1) - else() - # Oops. ENABLE_LIBSVN is ON, but svn is still missing. - # Provide clearly visible warning/hint, so builders know what else they should install (or disable). - message(WARNING "Failed to enable subversion client support. Unable to find required subversion client library. Some features may not be available (scenery download).") - message(WARNING "Install 'libsvn' library/DLL (libsvn-devel/libsvnclient/...). Otherwise disable subversion support (set 'ENABLE_LIBSVN' to 'OFF').") - endif(LIBSVN_FOUND) -else() - message(STATUS "Subversion client support: DISABLED") -endif(ENABLE_LIBSVN) - find_package(ZLIB REQUIRED) find_package(Threads REQUIRED) @@ -215,12 +197,19 @@ message(STATUS "Requested to use system Expat library, forcing SIMGEAR_SHARED to true") set(SIMGEAR_SHARED ON) find_package(EXPAT REQUIRED) - include_directories(${EXPAT_INCLUDE_DIRS}) + else() message(STATUS "Using built-in expat code") - add_definitions(-DHAVE_EXPAT_CONFIG_H) + # XML_STATIC is important to avoid sg_expat_external.h + # declaring symbols as declspec(import) + add_definitions(-DHAVE_EXPAT_CONFIG_H -DXML_STATIC) + set(EXPAT_INCLUDE_DIRS + ${PROJECT_SOURCE_DIR}/3rdparty/expat + ${PROJECT_BINARY_DIR}/3rdparty/expat) endif(SYSTEM_EXPAT) +include_directories(${EXPAT_INCLUDE_DIRS}) + check_include_file(inttypes.h HAVE_INTTYPES_H) check_include_file(sys/time.h HAVE_SYS_TIME_H) check_include_file(sys/timeb.h HAVE_SYS_TIMEB_H) @@ -269,6 +258,20 @@ endif(HAVE_RT) endif(HAVE_CLOCK_GETTIME) +set(DL_LIBRARY "") +check_cxx_source_compiles( + "#include + int main(void) { + return 0; + } + " + HAVE_DLFCN_H) + +if(HAVE_DLFCN_H) + check_library_exists(dl dlerror "" HAVE_DL) + set(DL_LIBRARY "dl") +endif() + SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "add a postfix, usually 'd' on windows") SET(CMAKE_RELEASE_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows") SET(CMAKE_RELWITHDEBINFO_POSTFIX "" CACHE STRING "add a postfix, usually empty on windows") @@ -302,6 +305,14 @@ set(WARNING_FLAGS_C "-Wall") endif() +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") +# boost goes haywire wrt static asserts + check_cxx_compiler_flag(-Wno-unused-local-typedefs HAS_NOWARN_UNUSED_TYPEDEFS) + if(HAS_NOWARN_UNUSED_TYPEDEFS) + set(WARNING_FLAGS_CXX " ${WARNING_FLAGS_CXX} -Wno-unused-local-typedefs") + endif() +endif() + if(WIN32) if(MINGW) @@ -314,7 +325,10 @@ # SET(WARNING_FLAGS "${WARNING_FLAGS} /wd${warning}") # endforeach(warning) - set(MSVC_FLAGS "-DWIN32 -DNOMINMAX -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -D__CRT_NONSTDC_NO_WARNINGS /wd4996 /wd4250") + set(MSVC_FLAGS "-DWIN32 -DNOMINMAX -D_USE_MATH_DEFINES -D_CRT_SECURE_NO_WARNINGS -D__CRT_NONSTDC_NO_WARNINGS /wd4996 /wd4250 -Dstrdup=_strdup") + if (${MSVC_VERSION} GREATER 1599) + set( MSVC_LD_FLAGS "/FORCE:MULTIPLE" ) + endif (${MSVC_VERSION} GREATER 1599) endif(MSVC) # assumed on Windows @@ -326,15 +340,17 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}") include_directories(${PROJECT_SOURCE_DIR}) include_directories(${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include) include_directories(${PROJECT_BINARY_DIR}/simgear) -include_directories(${PROJECT_BINARY_DIR}/simgear/xml) include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR} - ${OPENAL_INCLUDE_DIR} ) + ${Boost_INCLUDE_DIRS} + ${ZLIB_INCLUDE_DIR} + ${OPENAL_INCLUDE_DIR} +) add_definitions(-DHAVE_CONFIG_H) @@ -345,22 +361,33 @@ "${PROJECT_BINARY_DIR}/simgear/simgear_config.h" ) -configure_file ( - "${PROJECT_SOURCE_DIR}/simgear/xml/expat_config_cmake.in" - "${PROJECT_BINARY_DIR}/simgear/xml/expat_config.h" -) - if(ENABLE_TESTS) # enable CTest / make test target message(STATUS "Tests: ENABLED") include (Dart) - enable_testing() + enable_testing() else() message(STATUS "Tests: DISABLED") endif(ENABLE_TESTS) +# always set TEST_LIBS as it is also used by other tools/applications +set(TEST_LIBS_INTERNAL_CORE + ${CMAKE_THREAD_LIBS_INIT} + ${ZLIB_LIBRARY} + ${WINSOCK_LIBRARY} + ${RT_LIBRARY} + ${DL_LIBRARY} + ${CORE_SERVICES_LIBRARY}) +set(TEST_LIBS SimGearCore ${TEST_LIBS_INTERNAL_CORE}) + +if(NOT SIMGEAR_HEADLESS) + set(TEST_LIBS SimGearScene ${OPENGL_LIBRARIES} ${TEST_LIBS}) +endif() + install (FILES ${PROJECT_BINARY_DIR}/simgear/simgear_config.h DESTINATION include/simgear/) + +add_subdirectory(3rdparty) add_subdirectory(simgear) #----------------------------------------------------------------------------- @@ -372,3 +399,5 @@ IMMEDIATE @ONLY) ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") + + diff -Nru simgear-2.10.0/CMakeModules/FindSvnClient.cmake simgear-3.0.0/CMakeModules/FindSvnClient.cmake --- simgear-2.10.0/CMakeModules/FindSvnClient.cmake 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/CMakeModules/FindSvnClient.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,83 +0,0 @@ -# Find Subversion client libraries, and dependencies -# including APR (Apache Portable Runtime) - -include (CheckFunctionExists) -include (CheckIncludeFile) -include (CheckLibraryExists) - -macro(find_static_component comp libs) - # account for alternative Windows svn distribution naming - if(MSVC) - set(compLib "lib${comp}") - else(MSVC) - set(compLib "${comp}") - endif(MSVC) - - string(TOUPPER "${comp}" compLibBase) - set( compLibName ${compLibBase}_LIBRARY ) - - # NO_DEFAULT_PATH is important on Mac - we need to ensure subversion - # libraires in dist/ or Macports are picked over the Apple version - # in /usr, since that's what we will ship. - # On other platforms we do need default paths though, i.e. since Linux - # distros may use architecture-specific directories (like - # /usr/lib/x86_64-linux-gnu) which we cannot hardcode/guess here. - FIND_LIBRARY(${compLibName} -if(APPLE) - NO_DEFAULT_PATH -endif(APPLE) - NAMES ${compLib} - HINTS $ENV{LIBSVN_DIR} ${CMAKE_INSTALL_PREFIX} ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/lib - PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64 - PATHS ${ADDITIONAL_LIBRARY_PATHS} - ) - - list(APPEND ${libs} ${${compLibName}}) -endmacro() - -find_program(HAVE_APR_CONFIG apr-1-config) -if(HAVE_APR_CONFIG) - - execute_process(COMMAND apr-1-config --cppflags --includes - OUTPUT_VARIABLE APR_CFLAGS - OUTPUT_STRIP_TRAILING_WHITESPACE) - - execute_process(COMMAND apr-1-config --link-ld - OUTPUT_VARIABLE RAW_APR_LIBS - OUTPUT_STRIP_TRAILING_WHITESPACE) - -# clean up some vars, or other CMake pieces complain - string(STRIP "${RAW_APR_LIBS}" APR_LIBS) - -else(HAVE_APR_CONFIG) - message(STATUS "apr-1-config not found, implement manual search for APR") -endif(HAVE_APR_CONFIG) - -if(HAVE_APR_CONFIG OR MSVC) - find_path(LIBSVN_INCLUDE_DIR svn_client.h - NO_DEFAULT_PATH - HINTS - $ENV{LIBSVN_DIR} ${CMAKE_INSTALL_PREFIX} ${MSVC_3RDPARTY_ROOT}/${MSVC_3RDPARTY_DIR}/include - PATH_SUFFIXES include/subversion-1 - PATHS - /opt/local - /usr/local - /usr - ) - - set(LIBSVN_LIBRARIES "") - if (MSVC) - find_static_component("apr-1" LIBSVN_LIBRARIES) - else (MSVC) - list(APPEND LIBSVN_LIBRARIES ${APR_LIBS}) - endif (MSVC) - find_static_component("svn_client-1" LIBSVN_LIBRARIES) - find_static_component("svn_subr-1" LIBSVN_LIBRARIES) - find_static_component("svn_ra-1" LIBSVN_LIBRARIES) - - include(FindPackageHandleStandardArgs) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBSVN DEFAULT_MSG LIBSVN_LIBRARIES LIBSVN_INCLUDE_DIR) - if(NOT LIBSVN_FOUND) - set(LIBSVN_LIBRARIES "") - endif(NOT LIBSVN_FOUND) -endif(HAVE_APR_CONFIG OR MSVC) diff -Nru simgear-2.10.0/debian/changelog simgear-3.0.0/debian/changelog --- simgear-2.10.0/debian/changelog 2013-11-21 05:33:33.000000000 +0000 +++ simgear-3.0.0/debian/changelog 2014-02-19 16:35:31.000000000 +0000 @@ -1,8 +1,51 @@ -simgear (2.10.0-6ubuntu1) trusty; urgency=low +simgear (3.0.0-1) unstable; urgency=medium - * Rebuild against latest openscenegraph/libav. + [ Markus Wanner ] + * New upstream release. + * Drop the md5 replacement patch - applied upstream. + * Adjust watchfile to properly account for release candidates. + + [ Rebecca Palmer ] + * Replace sgstream_ignore_write_error.patch with a real fix in + sgstream_test_fix_length.patch and respect test suite results, again. + + -- Markus Wanner Wed, 19 Feb 2014 08:35:13 -0800 + +simgear (3.0.0~git20140204+c99ea4-1) unstable; urgency=low + + [ Markus Wanner ] + * New intermediate snapshot pre 3.0.0. + * Update debian/copyright. (Doesn't quite close #737733, though). + * Temporarily ignore test suite failures to unblock the openscenegraph + transition. + * Add a patch to replace the given md5 implementation. + + [ Rebecca Palmer ] + * Don't fail stream test if unable to set up test file. + * Enable verbose test output. + + -- Markus Wanner Thu, 06 Feb 2014 21:19:24 +0100 + +simgear (3.0.0~git20140123+f16c99-1) unstable; urgency=low + + * New upstream release. + * Automate adjustment of .install and .shlibs via clean target in + debian/rules. + * Bump Standards-Version to 3.9.5; no changes needed. + * Drop patch cppbind-charsignedness.diff, it got applied upstream. + * Drop the libsvn-dev dependency, simgear now provides its own svn + client. + + -- Markus Wanner Wed, 22 Jan 2014 22:48:02 +0100 + +simgear (2.12.0-1) experimental; urgency=low + + * New upstream release. + * Adjust .install and .shlibs files accordingly. + * Drop patches gcc-macro-correction.diff, osg-compat.diff, + CVE-2012-2090.diff CVE-2012-2091.diff. These got applied upstream. - -- Timo Aaltonen Thu, 21 Nov 2013 07:31:51 +0200 + -- Markus Wanner Sun, 22 Sep 2013 21:15:48 +0200 simgear (2.10.0-6) unstable; urgency=low @@ -434,6 +477,5 @@ -- Ove Kaaven Tue, 6 Feb 2001 13:06:57 +0100 Local variables: -mode: debian-changelog add-log-mailing-address "ovek@arcticnet.no" End: diff -Nru simgear-2.10.0/debian/control simgear-3.0.0/debian/control --- simgear-2.10.0/debian/control 2013-11-21 05:33:45.000000000 +0000 +++ simgear-3.0.0/debian/control 2014-02-19 16:57:11.000000000 +0000 @@ -1,24 +1,23 @@ Source: simgear Section: libs Priority: extra -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Debian FlightGear Crew +Maintainer: Debian FlightGear Crew Uploaders: Ove Kaaven , Markus Wanner Build-Depends: debhelper (>= 8.1.3), libx11-dev, libxext-dev, libxi-dev, libice-dev, libsm-dev, libxt-dev, libxmu-dev, zlib1g-dev, libboost-dev, - libopenal-dev, libalut-dev, libsvn-dev, libexpat1-dev, cmake (>= 2.6), + libopenal-dev, libalut-dev, libexpat1-dev, cmake (>= 2.6), libgl1-mesa-dev | libgl-dev, libglu1-mesa-dev | libglu-dev, freeglut3-dev | libglut3-dev, libjpeg8-dev | libjpeg62-dev | libjpeg-dev, libopenscenegraph-dev (>> 3.0.0) -Standards-Version: 3.9.4 +Standards-Version: 3.9.5 Homepage: http://www.simgear.org/ Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/simgear.git Vcs-Git: git://anonscm.debian.org/collab-maint/simgear.git -Package: libsimgearcore2.10.0 +Package: libsimgearcore3.0.0 Architecture: any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} @@ -31,12 +30,12 @@ . This package contains the core library. -Package: libsimgearcore2.10.0-dbg +Package: libsimgearcore3.0.0-dbg Architecture: any Section: debug Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} -Depends: libsimgearcore2.10.0 (= ${binary:Version}), +Depends: libsimgearcore3.0.0 (= ${binary:Version}), ${misc:Depends} Description: debugging symbols for libsimgearcore SimGear is a collection of libraries useful for constructing @@ -45,11 +44,11 @@ . This package contains the debug symbols for the core library. -Package: libsimgearscene2.10.0 +Package: libsimgearscene3.0.0 Architecture: any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} -Depends: libsimgearcore2.10.0 (= ${binary:Version}), +Depends: libsimgearcore3.0.0 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} Conflicts: simgear0 Description: Simulator Construction Gear -- scene library @@ -59,12 +58,12 @@ . This package contains the scene library. -Package: libsimgearscene2.10.0-dbg +Package: libsimgearscene3.0.0-dbg Architecture: any Section: debug Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} -Depends: libsimgearcore2.10.0 (= ${binary:Version}), +Depends: libsimgearcore3.0.0 (= ${binary:Version}), ${misc:Depends} Conflicts: simgear0 Description: debugging symbols for libsimgearscene @@ -77,8 +76,8 @@ Package: libsimgear-dev Architecture: any Section: libdevel -Depends: libsimgearcore2.10.0 (= ${binary:Version}), - libsimgearscene2.10.0 (= ${binary:Version}), +Depends: libsimgearcore3.0.0 (= ${binary:Version}), + libsimgearscene3.0.0 (= ${binary:Version}), libopenscenegraph-dev, libc6-dev, ${misc:Depends} Replaces: simgear-dev (<< 2.10.0~) Breaks: simgear-dev (<< 2.10.0~) diff -Nru simgear-2.10.0/debian/control.in simgear-3.0.0/debian/control.in --- simgear-2.10.0/debian/control.in 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/debian/control.in 2014-02-17 14:48:47.000000000 +0000 @@ -0,0 +1,96 @@ +Source: simgear +Section: libs +Priority: extra +Maintainer: Debian FlightGear Crew +Uploaders: Ove Kaaven , + Markus Wanner +Build-Depends: debhelper (>= 8.1.3), libx11-dev, libxext-dev, libxi-dev, + libice-dev, libsm-dev, libxt-dev, libxmu-dev, zlib1g-dev, libboost-dev, + libopenal-dev, libalut-dev, libexpat1-dev, cmake (>= 2.6), + libgl1-mesa-dev | libgl-dev, + libglu1-mesa-dev | libglu-dev, + freeglut3-dev | libglut3-dev, + libjpeg8-dev | libjpeg62-dev | libjpeg-dev, + libopenscenegraph-dev (>> 3.0.0) +Standards-Version: 3.9.5 +Homepage: http://www.simgear.org/ +Vcs-Browser: http://anonscm.debian.org/gitweb/?p=collab-maint/simgear.git +Vcs-Git: git://anonscm.debian.org/collab-maint/simgear.git + +Package: libsimgearcore##UVER +Architecture: any +Multi-Arch: same +Pre-Depends: ${misc:Pre-Depends} +Depends: ${shlibs:Depends}, ${misc:Depends} +Conflicts: simgear0 +Description: Simulator Construction Gear -- core library + SimGear is a collection of libraries useful for constructing + simulation and visualization applications such as FlightGear + or TerraGear. + . + This package contains the core library. + +Package: libsimgearcore##UVER-dbg +Architecture: any +Section: debug +Multi-Arch: same +Pre-Depends: ${misc:Pre-Depends} +Depends: libsimgearcore##UVER (= ${binary:Version}), + ${misc:Depends} +Description: debugging symbols for libsimgearcore + SimGear is a collection of libraries useful for constructing + simulation and visualization applications such as FlightGear + or TerraGear. + . + This package contains the debug symbols for the core library. + +Package: libsimgearscene##UVER +Architecture: any +Multi-Arch: same +Pre-Depends: ${misc:Pre-Depends} +Depends: libsimgearcore##UVER (= ${binary:Version}), + ${shlibs:Depends}, ${misc:Depends} +Conflicts: simgear0 +Description: Simulator Construction Gear -- scene library + SimGear is a collection of libraries useful for constructing + simulation and visualization applications such as FlightGear + or TerraGear. + . + This package contains the scene library. + +Package: libsimgearscene##UVER-dbg +Architecture: any +Section: debug +Multi-Arch: same +Pre-Depends: ${misc:Pre-Depends} +Depends: libsimgearcore##UVER (= ${binary:Version}), + ${misc:Depends} +Conflicts: simgear0 +Description: debugging symbols for libsimgearscene + SimGear is a collection of libraries useful for constructing + simulation and visualization applications such as FlightGear + or TerraGear. + . + This package contains the debug symbols for the scene library. + +Package: libsimgear-dev +Architecture: any +Section: libdevel +Depends: libsimgearcore##UVER (= ${binary:Version}), + libsimgearscene##UVER (= ${binary:Version}), + libopenscenegraph-dev, libc6-dev, ${misc:Depends} +Replaces: simgear-dev (<< 2.10.0~) +Breaks: simgear-dev (<< 2.10.0~) +Description: Simulator Construction Gear -- development files + SimGear is a collection of libraries useful for constructing + simulation and visualization applications such as FlightGear + or TerraGear. + . + This package contains the headers and static libraries. + +Package: simgear-dev +Depends: libsimgear-dev, ${misc:Depends} +Architecture: all +Section: oldlibs +Description: transitional dummy package + This is a transitional dummy package. It can safely be removed. diff -Nru simgear-2.10.0/debian/copyright simgear-3.0.0/debian/copyright --- simgear-2.10.0/debian/copyright 2013-09-20 13:40:43.000000000 +0000 +++ simgear-3.0.0/debian/copyright 2014-02-17 14:48:47.000000000 +0000 @@ -16,9 +16,9 @@ 2006-2012 Mathias Froehlich - Mathias.Froehlich@web.de 2008-2010 Tim Moore timoore33@gmail.com 2010 Tim Moore moore@bricoworks.com - 2003,2010,2012 James Turner + 2003,2010,2012,2013 James Turner 2010-2011 Frederic Bouvier (fredfgfs01@free.fr) - 2012 Thomas Geymayer + 2012,2013 Thomas Geymayer 2012 Thorsten Brehm, brehmt at gmail dt com and the the FlightGear team (see the Thanks file). License: LGPL-2+ @@ -55,6 +55,16 @@ simgear/scene/material/matmodel.cxx simgear/scene/material/matmodel.hxx simgear/scene/material/EffectGeode.cxx + simgear/io/iochannel.?xx + simgear/io/lowlevel.cxx + simgear/io/sg_binobj.?xx + simgear/io/sg_file.?xx + simgear/io/sg_serial.?xx + simgear/io/sg_socket.?xx + simgear/io/sg_socket_udp.?xx + simgear/io/SVNDirectory.?xx + simgear/io/SVNReportParser.?xx + simgear/io/SVNRepository.?xx Copyright: 1998-2003 Curtis L. Olson - http://www.flightgear.org/~curt 2008 Timothy Moore timoore@redhat.com License: GPL-2+ @@ -127,6 +137,15 @@ Copyright: 2003 FlightGear Flight Simulator License: GPL-2+ +Files: simgear/io/DAVMultiStatus.cxx +Copyright: 2012 James Turner +License: GPL-2+ + +Files: simgear/io/lowlevel.?xx +Copyright: 2000 the plib team + 2000 Curtis L. Olson +License: GPL-2+ + Files: simgear/screen/extensions.?xx Copyright: 2001 César Blecua Udías License: MIT-CESAR-BLECUA-UDIAS @@ -139,15 +158,26 @@ Copyright: 2000 Stephen Cleary License: BSL-1.0 -Files: simgear/xml/* +Files: 3rdparty/expat/* Copyright: 1998, 1999, 2000 Thai Open Source Software Center Ltd and Clark Cooper - 1998-1999 James Clark 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers. License: Expat +Files: simgear/package/unzip.? + simgear/package/ioapi.? + simgear/package/ioapi_mem.c +Copyright: 1998-2009 Gilles Vollant + 2003 Justin Fletcher +License: zlib + +Files: simgear/package/md5.? +Copyright: 1990 RSA Data Security, Inc. +License: bsd-with-advertising-clause + Files: simgear/scene/model/animation.?xx simgear/scene/model/model.?xx simgear/scene/model/placement.?xx + simgear/xml/easyxml.?xx Copyright: *No copyright* License: public-domain These files are in the Public Domain, and come with no warranty. @@ -277,3 +307,39 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License: zlib + 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. + +License: bsd-with-advertising-clause + License to copy and use this software is granted provided that + it is identified as the "RSA Data Security, Inc. MD5 Message + Digest Algorithm" in all material mentioning or referencing this + software or this function. + . + License is also granted to make and use derivative works + provided that such works are identified as "derived from the RSA + Data Security, Inc. MD5 Message Digest Algorithm" in all + material mentioning or referencing the derived work. + . + RSA Data Security, Inc. makes no representations concerning + either the merchantability of this software or the suitability + of this software for any particular purpose. It is provided "as + is" without express or implied warranty of any kind. + . + These notices must be retained in any copies of any part of this + documentation and/or software. diff -Nru simgear-2.10.0/debian/libsimgearcore2.10.0.install simgear-3.0.0/debian/libsimgearcore2.10.0.install --- simgear-2.10.0/debian/libsimgearcore2.10.0.install 2013-09-20 13:40:43.000000000 +0000 +++ simgear-3.0.0/debian/libsimgearcore2.10.0.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/*/libSimGearCore.so.2.10* diff -Nru simgear-2.10.0/debian/libsimgearcore2.10.0.shlibs simgear-3.0.0/debian/libsimgearcore2.10.0.shlibs --- simgear-2.10.0/debian/libsimgearcore2.10.0.shlibs 2013-09-20 13:40:43.000000000 +0000 +++ simgear-3.0.0/debian/libsimgearcore2.10.0.shlibs 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -libSimGearCore 2.10.0 libsimgearcore2.10.0 (>= 2.10.0~) diff -Nru simgear-2.10.0/debian/libsimgearcore3.0.0.install simgear-3.0.0/debian/libsimgearcore3.0.0.install --- simgear-2.10.0/debian/libsimgearcore3.0.0.install 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/debian/libsimgearcore3.0.0.install 2014-02-19 16:57:11.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/*/libSimGearCore.so.* diff -Nru simgear-2.10.0/debian/libsimgearcore3.0.0.shlibs simgear-3.0.0/debian/libsimgearcore3.0.0.shlibs --- simgear-2.10.0/debian/libsimgearcore3.0.0.shlibs 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/debian/libsimgearcore3.0.0.shlibs 2014-02-19 16:57:11.000000000 +0000 @@ -0,0 +1 @@ +libSimGearCore 3.0.0 libsimgearcore3.0.0 (>= 3.0.0~) diff -Nru simgear-2.10.0/debian/libsimgearscene2.10.0.install simgear-3.0.0/debian/libsimgearscene2.10.0.install --- simgear-2.10.0/debian/libsimgearscene2.10.0.install 2013-09-20 13:40:43.000000000 +0000 +++ simgear-3.0.0/debian/libsimgearscene2.10.0.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/*/libSimGearScene.so.2.10* diff -Nru simgear-2.10.0/debian/libsimgearscene2.10.0.shlibs simgear-3.0.0/debian/libsimgearscene2.10.0.shlibs --- simgear-2.10.0/debian/libsimgearscene2.10.0.shlibs 2013-09-20 13:40:43.000000000 +0000 +++ simgear-3.0.0/debian/libsimgearscene2.10.0.shlibs 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -libSimGearScene 2.10.0 libsimgearscene2.10.0 (>= 2.10.0~) diff -Nru simgear-2.10.0/debian/libsimgearscene3.0.0.install simgear-3.0.0/debian/libsimgearscene3.0.0.install --- simgear-2.10.0/debian/libsimgearscene3.0.0.install 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/debian/libsimgearscene3.0.0.install 2014-02-19 16:57:11.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/*/libSimGearScene.so.* diff -Nru simgear-2.10.0/debian/libsimgearscene3.0.0.shlibs simgear-3.0.0/debian/libsimgearscene3.0.0.shlibs --- simgear-2.10.0/debian/libsimgearscene3.0.0.shlibs 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/debian/libsimgearscene3.0.0.shlibs 2014-02-19 16:57:11.000000000 +0000 @@ -0,0 +1 @@ +libSimGearScene 3.0.0 libsimgearscene3.0.0 (>= 3.0.0~) diff -Nru simgear-2.10.0/debian/patches/cppbind-charsignedness.diff simgear-3.0.0/debian/patches/cppbind-charsignedness.diff --- simgear-2.10.0/debian/patches/cppbind-charsignedness.diff 2013-09-20 13:40:43.000000000 +0000 +++ simgear-3.0.0/debian/patches/cppbind-charsignedness.diff 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -Subject: correct signedness of 'emblen' in struct naStr. -From: Rebecca Palmer -Last-Update: 2013-09-13 - ---- a/simgear/nasal/data.h -+++ b/simgear/nasal/data.h -@@ -96,7 +96,7 @@ - #define MAX_STR_EMBLEN 15 - struct naStr { - GC_HEADER; -- char emblen; /* [0-15], or -1 to indicate "not embedded" */ -+ signed char emblen; /* [0-15], or -1 to indicate "not embedded" */ - unsigned int hashcode; - union { - unsigned char buf[16]; diff -Nru simgear-2.10.0/debian/patches/CVE-2012-2090.diff simgear-3.0.0/debian/patches/CVE-2012-2090.diff --- simgear-2.10.0/debian/patches/CVE-2012-2090.diff 2013-09-20 13:40:43.000000000 +0000 +++ simgear-3.0.0/debian/patches/CVE-2012-2090.diff 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -Subject: Fix for CVE-2012-2090: prevent %n being passed to format strings - CVE-2012-2090 mentions multiple places in simgear and flightgear that - allow an unsafe %n specifier to be passed as a format string. This patch - prevents this for simgear's SGText::UpdateCallback() constructor. -From: Saikrishna Arcot -Origin: https://bugs.launchpad.net/ubuntu/+source/flightgear/+bug/1077624/+attachment/3805987/+files/cve-2012-2090-check-for-%25n-in-printf-format.patch -Last-Update: 2013-09-06 - ---- a/simgear/scene/model/SGText.cxx -+++ b/simgear/scene/model/SGText.cxx -@@ -46,6 +46,15 @@ - if( format.size() == 0 ) { - if( numeric ) format = "%f"; - else format = "%s"; -+ } else { -+ // It is never safe for format to be %n. -+ string unsafe ("%n"); -+ size_t found; -+ found=format.find(unsafe); -+ if (found!=string::npos) { -+ SG_LOG(SG_COCKPIT, SG_WARN, "format type contained %n, but this is unsafe, reverting to %s"); -+ format = "%s"; -+ } - } - } - diff -Nru simgear-2.10.0/debian/patches/CVE-2012-2091.diff simgear-3.0.0/debian/patches/CVE-2012-2091.diff --- simgear-2.10.0/debian/patches/CVE-2012-2091.diff 2013-09-20 13:40:43.000000000 +0000 +++ simgear-3.0.0/debian/patches/CVE-2012-2091.diff 1970-01-01 00:00:00.000000000 +0000 @@ -1,49 +0,0 @@ -Subject: Fix for CVE-2012-2091: add checks against buffer overruns - CVE-2012-2091 mentions various buffer overruns in simgear and - flightgear. This patch addresses issues in SGSocketUDP::read() and - SGSocketUDP::readline() - for simgear only, obviously. -From: Rebecca Palmer, Saikrishna Arcot -Origin: https://bugs.launchpad.net/ubuntu/+source/flightgear/+bug/1077624/+attachment/3806309/+files/simgear_CVE2012_2091.patch -Last-Update: 2013-09-07 - ---- a/simgear/io/sg_socket_udp.cxx -+++ b/simgear/io/sg_socket_udp.cxx -@@ -103,9 +103,13 @@ - return 0; - } - -+ if (length <= 0) { -+ return 0; -+ } - int result; -+ int maxsize = (length - 1) < SG_IO_MAX_MSG_SIZE ? (length - 1) : SG_IO_MAX_MSG_SIZE; - -- if ( (result = sock.recv(buf, SG_IO_MAX_MSG_SIZE, 0)) >= 0 ) { -+ if ( (result = sock.recv(buf, maxsize, 0)) >= 0 ) { - buf[result] = '\0'; - // printf("msg received = %s\n", buf); - } -@@ -120,10 +124,14 @@ - return 0; - } - -+ if (length <= 0) { -+ return 0; -+ } - // cout << "sock = " << sock << endl; - - char *buf_ptr = save_buf + save_len; -- int result = sock.recv(buf_ptr, SG_IO_MAX_MSG_SIZE, 0); -+ int maxsize = save_len < SG_IO_MAX_MSG_SIZE ? SG_IO_MAX_MSG_SIZE : 2 * SG_IO_MAX_MSG_SIZE - save_len; //prevent buffer overflow (size of save_buf is 2 * SG_IO_MAX_MSG_SIZE) -+ int result = sock.recv(buf_ptr, maxsize, 0); - // printf("msg received = %s\n", buf); - save_len += result; - -@@ -142,6 +150,7 @@ - // we found an end of line - - // copy to external buffer -+ result = result < (length - 1) ? result : (length - 1); //prevent buffer overflow - strncpy( buf, save_buf, result ); - buf[result] = '\0'; - // cout << "sg_socket line = " << buf << endl; diff -Nru simgear-2.10.0/debian/patches/gcc-macro-correction.diff simgear-3.0.0/debian/patches/gcc-macro-correction.diff --- simgear-2.10.0/debian/patches/gcc-macro-correction.diff 2013-09-20 13:40:43.000000000 +0000 +++ simgear-3.0.0/debian/patches/gcc-macro-correction.diff 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -Subject: Back-port compatibility with OpenSceneGraph 3.2 -From: Markus Wanner -Last-Update: 2013-08-22 - ---- a/simgear/compiler.h -+++ b/simgear/compiler.h -@@ -46,7 +46,7 @@ - # warning GCC compilers prior to 3.4 are suspect - # endif - --# define GCC_VERSION (__GNUC__ * 10000 \ -+# define SG_GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) - # define SG_COMPILER_STR "GNU C++ version " SG_STRINGIZE(__GNUC__) "." SG_STRINGIZE(__GNUC_MINOR__) ---- a/simgear/nasal/cppbind/Ghost.hxx -+++ b/simgear/nasal/cppbind/Ghost.hxx -@@ -281,7 +281,7 @@ - // Both ways of retrieving the address of a static member function - // should be legal but not all compilers know this. - // g++-4.4.7+ has been tested to work with both versions --#if defined(GCC_VERSION) && GCC_VERSION < 40407 -+#if defined(SG_GCC_VERSION) && SG_GCC_VERSION < 40407 - // The old version of g++ used on Jenkins (16.11.2012) only compiles - // this version. - &getTypeFor diff -Nru simgear-2.10.0/debian/patches/osg-compat.diff simgear-3.0.0/debian/patches/osg-compat.diff --- simgear-2.10.0/debian/patches/osg-compat.diff 2013-09-20 13:40:43.000000000 +0000 +++ simgear-3.0.0/debian/patches/osg-compat.diff 1970-01-01 00:00:00.000000000 +0000 @@ -1,43 +0,0 @@ -Subject: Back-port compatibility with OpenSceneGraph 3.2 -From: Markus Wanner -Last-Update: 2013-07-31 - ---- a/simgear/scene/material/EffectGeode.cxx -+++ b/simgear/scene/material/EffectGeode.cxx -@@ -22,6 +22,8 @@ - #include "Effect.hxx" - #include "Technique.hxx" - -+#include -+ - #include - #include - -@@ -80,15 +82,27 @@ - int n = _effect->getGenerator(Effect::TANGENT); - tsg->generate(geometry, 0); // 0 is normal_unit, but I have no idea what that is! - if (n != -1 && !geometry->getVertexAttribArray(n)) -+#if OSG_MIN_VERSION_REQUIRED(3,1,8) -+ geometry->setVertexAttribArray(n, tsg->getTangentArray(), osg::Array::BIND_PER_VERTEX); -+#else - geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getTangentArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); -+#endif - - n = _effect->getGenerator(Effect::BINORMAL); - if (n != -1 && !geometry->getVertexAttribArray(n)) -+#if OSG_MIN_VERSION_REQUIRED(3,1,8) -+ geometry->setVertexAttribArray(n, tsg->getBinormalArray(), osg::Array::BIND_PER_VERTEX); -+#else - geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getBinormalArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); -+#endif - - n = _effect->getGenerator(Effect::NORMAL); - if (n != -1 && !geometry->getVertexAttribArray(n)) -+#if OSG_MIN_VERSION_REQUIRED(3,1,8) -+ geometry->setVertexAttribArray(n, tsg->getNormalArray(), osg::Array::BIND_PER_VERTEX); -+#else - geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getNormalArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); -+#endif - } - } - diff -Nru simgear-2.10.0/debian/patches/series simgear-3.0.0/debian/patches/series --- simgear-2.10.0/debian/patches/series 2013-09-20 17:22:07.000000000 +0000 +++ simgear-3.0.0/debian/patches/series 2014-02-17 17:10:34.000000000 +0000 @@ -1,5 +1 @@ -gcc-macro-correction.diff -osg-compat.diff -CVE-2012-2090.diff -CVE-2012-2091.diff -cppbind-charsignedness.diff +sgstream_test_fix_length.patch diff -Nru simgear-2.10.0/debian/patches/sgstream_test_fix_length.patch simgear-3.0.0/debian/patches/sgstream_test_fix_length.patch --- simgear-2.10.0/debian/patches/sgstream_test_fix_length.patch 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/debian/patches/sgstream_test_fix_length.patch 2014-02-17 17:10:02.000000000 +0000 @@ -0,0 +1,15 @@ +Description: Don't read past the end of the string +Author: Rebecca Palmer +Forwarded: no + +--- simgear-3.0.0~git20140204+c99ea4.orig/simgear/misc/sgstream_test.cxx ++++ simgear-3.0.0~git20140204+c99ea4/simgear/misc/sgstream_test.cxx +@@ -20,7 +20,7 @@ int main() + "third line ends with both\r\n" + "fourth line as well\r\n" + "fifth line is another CR/LF line\r\n" +- "end of test\r\n", 1024); ++ "end of test\r\n", 158); + f.close(); + } + diff -Nru simgear-2.10.0/debian/rules simgear-3.0.0/debian/rules --- simgear-2.10.0/debian/rules 2013-09-20 21:02:59.000000000 +0000 +++ simgear-3.0.0/debian/rules 2014-02-17 17:26:45.000000000 +0000 @@ -4,15 +4,20 @@ # debian/rules for simgear, by Markus Wanner # based on the dh7 template provided by dh_make(1) -#http://wiki.debian.org/Hardening#Notes_for_packages_using_CMake +# Get upstream version for automatic generation of some packaging files +UVER:=$(shell cat $(CURDIR)/version) + +# http://wiki.debian.org/Hardening#Notes_for_packages_using_CMake CPPFLAGS:=$(shell dpkg-buildflags --get CPPFLAGS) ifneq (,$(findstring $(DEB_HOST_ARCH) , amd64 i386 mipsel ia64 armel armhf arm64 )) + # Note the spaces in the condition above. They stop 'mips' from # matching 'mipsel' CFLAGS:=$(shell dpkg-buildflags --get CFLAGS) $(CPPFLAGS) CXXFLAGS:=$(shell dpkg-buildflags --get CXXFLAGS) $(CPPFLAGS) else -#required on big-endian architectures, see bug #722115 + +# Required on big-endian architectures, see bug #722115 CFLAGS:=$(shell dpkg-buildflags --get CFLAGS) $(CPPFLAGS) -fno-strict-aliasing CXXFLAGS:=$(shell dpkg-buildflags --get CXXFLAGS) $(CPPFLAGS) -fno-strict-aliasing endif @@ -33,13 +38,32 @@ %: dh $@ --buildsystem=cmake --builddirectory=build --parallel +override_dh_auto_clean: +# Generate a couple of files automatically, based on the given +# upsteram version. + cat $(CURDIR)/debian/control.in \ + | sed 's/\#\#UVER/$(UVER)/' > $(CURDIR)/debian/control + rm -f $(CURDIR)/debian/libsimgearcore*.shlibs $(CURDIR)/debian/libsimgearcore*.install + echo "libSimGearCore $(UVER) libsimgearcore$(UVER) (>= $(UVER)~)" \ + > $(CURDIR)/debian/libsimgearcore$(UVER).shlibs + echo "usr/lib/*/libSimGearCore.so.*" \ + > $(CURDIR)/debian/libsimgearcore$(UVER).install + + rm -f $(CURDIR)/debian/libsimgearscene*.shlibs $(CURDIR)/debian/libsimgearscene*.install + echo "libSimGearScene $(UVER) libsimgearscene$(UVER) (>= $(UVER)~)" \ + > $(CURDIR)/debian/libsimgearscene$(UVER).shlibs + echo "usr/lib/*/libSimGearScene.so.*" \ + > $(CURDIR)/debian/libsimgearscene$(UVER).install + + dh_auto_clean + override_dh_auto_configure: mkdir build cd build && cmake .. $(CMAKE_FLAGS) override_dh_strip: - dh_strip -plibsimgearcore2.10.0 --dbg-package=libsimgearcore2.10.0-dbg - dh_strip -plibsimgearscene2.10.0 --dbg-package=libsimgearscene2.10.0-dbg + dh_strip -plibsimgearcore$(UVER) --dbg-package=libsimgearcore$(UVER)-dbg + dh_strip -plibsimgearscene$(UVER) --dbg-package=libsimgearscene$(UVER)-dbg get-orig-source: uscan --download-current-version --verbose --rename diff -Nru simgear-2.10.0/debian/watch simgear-3.0.0/debian/watch --- simgear-2.10.0/debian/watch 2013-09-20 13:40:43.000000000 +0000 +++ simgear-3.0.0/debian/watch 2014-02-17 14:48:47.000000000 +0000 @@ -1,3 +1,3 @@ version=3 -#ftp://ftp.simgear.org/pub/simgear/Source/simgear-(.*)\.tar\.bz2 -ftp://mirrors.ibiblio.org/pub/mirrors/simgear/ftp/Source/simgear-(.*)\.tar\.bz2 +opts=uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha|b|a)\d*)$/$1~$2/ \ + ftp://mirrors.ibiblio.org/pub/mirrors/simgear/ftp/Source/simgear-(.*)\.tar\.bz2 diff -Nru simgear-2.10.0/Doxyfile simgear-3.0.0/Doxyfile --- simgear-2.10.0/Doxyfile 2011-01-03 13:58:48.000000000 +0000 +++ simgear-3.0.0/Doxyfile 2014-02-15 00:04:11.000000000 +0000 @@ -22,7 +22,7 @@ # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 2.2.0 +PROJECT_NUMBER = 2.11.0 # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. @@ -56,7 +56,7 @@ # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. -EXTRACT_STATIC = NO +EXTRACT_STATIC = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. diff -Nru simgear-2.10.0/simgear/bucket/newbucket.cxx simgear-3.0.0/simgear/bucket/newbucket.cxx --- simgear-2.10.0/simgear/bucket/newbucket.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/bucket/newbucket.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -212,7 +212,7 @@ main_lat *= -1; } - sprintf(raw_path, "%c%03d%c%02d/%c%03d%c%02d", + snprintf(raw_path, 256, "%c%03d%c%02d/%c%03d%c%02d", hem, top_lon, pole, top_lat, hem, main_lon, pole, main_lat); @@ -224,17 +224,6 @@ // return width of the tile in degrees double SGBucket::get_width() const { - if (lon==-180 && (lat==-89 || lat==88) ) { - /* Normally the tile at 180W in 88N and 89S - * would cover 184W to 176W and the next - * on the east side starts at 176W. - * To correct, make this a special tile - * from 180W to 176W with 4 degrees width - * instead of the normal 8 degrees at - * that latitude. - */ - return 4.0; - } return sg_bucket_span( get_center_lat() ); } @@ -356,4 +345,13 @@ #endif } +void sgGetBuckets( const SGGeod& min, const SGGeod& max, std::vector& list ) { + double lon, lat, span; + for (lat = min.getLatitudeDeg(); lat <= max.getLatitudeDeg(); lat += SG_BUCKET_SPAN) { + span = sg_bucket_span( lat ); + for (lon = min.getLongitudeDeg(); lon <= max.getLongitudeDeg(); lon += span) { + list.push_back( SGBucket(lon , lat) ); + } + } +} diff -Nru simgear-2.10.0/simgear/bucket/newbucket.hxx simgear-3.0.0/simgear/bucket/newbucket.hxx --- simgear-2.10.0/simgear/bucket/newbucket.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/bucket/newbucket.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -42,6 +42,7 @@ #include // sprintf() #include #include +#include /** * standard size of a bucket in degrees (1/8 of a degree) @@ -57,9 +58,7 @@ // return the horizontal tile span factor based on latitude static double sg_bucket_span( double l ) { if ( l >= 89.0 ) { - return 360.0; - } else if ( l >= 88.0 ) { - return 8.0; + return 12.0; } else if ( l >= 86.0 ) { return 4.0; } else if ( l >= 83.0 ) { @@ -80,12 +79,10 @@ return 1.0; } else if ( l >= -86.0 ) { return 2.0; - } else if ( l >= -88.0 ) { - return 4.0; } else if ( l >= -89.0 ) { - return 8.0; + return 4.0; } else { - return 360.0; + return 12.0; } } @@ -327,6 +324,15 @@ /** + * \relates SGBucket + * retrieve a list of buckets in the given bounding box + * @param min min lon,lat of bounding box in degrees + * @param max max lon,lat of bounding box in degrees + * @param list standard vector of buckets within the bounding box + */ +void sgGetBuckets( const SGGeod& min, const SGGeod& max, std::vector& list ); + +/** * Write the bucket lon, lat, x, and y to the output stream. * @param out output stream * @param b bucket diff -Nru simgear-2.10.0/simgear/canvas/Canvas.cxx simgear-3.0.0/simgear/canvas/Canvas.cxx --- simgear-2.10.0/simgear/canvas/Canvas.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/Canvas.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -31,7 +31,6 @@ #include #include -#include namespace simgear { @@ -82,16 +81,13 @@ } //---------------------------------------------------------------------------- - void Canvas::setSystemAdapter(const SystemAdapterPtr& system_adapter) - { - _system_adapter = system_adapter; - _texture.setSystemAdapter(system_adapter); - } - - //---------------------------------------------------------------------------- - SystemAdapterPtr Canvas::getSystemAdapter() const + void Canvas::onDestroy() { - return _system_adapter; + if( _root_group ) + { + _root_group->clearEventListener(); + _root_group->onDestroy(); + } } //---------------------------------------------------------------------------- @@ -107,7 +103,13 @@ } //---------------------------------------------------------------------------- - void Canvas::addDependentCanvas(const CanvasWeakPtr& canvas) + bool Canvas::isInit() const + { + return _texture.serviceable(); + } + + //---------------------------------------------------------------------------- + void Canvas::addParentCanvas(const CanvasWeakPtr& canvas) { if( canvas.expired() ) { @@ -115,28 +117,67 @@ ( SG_GENERAL, SG_WARN, - "Canvas::addDependentCanvas: got an expired Canvas dependent on " - << _node->getPath() + "Canvas::addParentCanvas(" << _node->getPath(true) << "): " + "got an expired parent!" ); return; } - _dependent_canvases.insert(canvas); + _parent_canvases.insert(canvas); } //---------------------------------------------------------------------------- - void Canvas::removeDependentCanvas(const CanvasWeakPtr& canvas) + void Canvas::addChildCanvas(const CanvasWeakPtr& canvas) { - _dependent_canvases.erase(canvas); + if( canvas.expired() ) + { + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "Canvas::addChildCanvas(" << _node->getPath(true) << "): " + " got an expired child!" + ); + return; + } + + _child_canvases.insert(canvas); + } + + //---------------------------------------------------------------------------- + void Canvas::removeParentCanvas(const CanvasWeakPtr& canvas) + { + _parent_canvases.erase(canvas); + } + + //---------------------------------------------------------------------------- + void Canvas::removeChildCanvas(const CanvasWeakPtr& canvas) + { + _child_canvases.erase(canvas); } //---------------------------------------------------------------------------- GroupPtr Canvas::createGroup(const std::string& name) { - return boost::dynamic_pointer_cast - ( - _root_group->createChild("group", name) - ); + return _root_group->createChild(name); + } + + //---------------------------------------------------------------------------- + GroupPtr Canvas::getGroup(const std::string& name) + { + return _root_group->getChild(name); + } + + //---------------------------------------------------------------------------- + GroupPtr Canvas::getOrCreateGroup(const std::string& name) + { + return _root_group->getOrCreateChild(name); + } + + //---------------------------------------------------------------------------- + GroupPtr Canvas::getRootGroup() + { + return _root_group; } //---------------------------------------------------------------------------- @@ -168,24 +209,21 @@ { // Resizing causes a new texture to be created so we need to reapply all // existing placements - for(size_t i = 0; i < _placements.size(); ++i) - { - if( !_placements[i].empty() ) - _dirty_placements.push_back( _placements[i].front()->getProps() ); - } + reloadPlacements(); } osg::Camera* camera = _texture.getCamera(); + // TODO Allow custom render order? For now just keep in order with + // property tree. + camera->setRenderOrder(osg::Camera::PRE_RENDER, _node->getIndex()); + osg::Vec4 clear_color(0.0f, 0.0f, 0.0f , 1.0f); parseColor(_node->getStringValue("background"), clear_color); camera->setClearColor(clear_color); camera->addChild(_root_group->getMatrixTransform()); - // Ensure objects are drawn in order of traversal - camera->getOrCreateStateSet()->setBinName("TraversalOrderBin"); - if( _texture.serviceable() ) { setStatusFlags(STATUS_OK); @@ -201,10 +239,18 @@ if( _visible || _render_always ) { + BOOST_FOREACH(CanvasWeakPtr canvas, _child_canvases) + { + // TODO should we check if the image the child canvas is displayed + // within is really visible? + if( !canvas.expired() ) + canvas.lock()->_visible = true; + } + if( _render_dirty ) { - // Also mark all dependent (eg. recursively used) canvases as dirty - BOOST_FOREACH(CanvasWeakPtr canvas, _dependent_canvases) + // Also mark all canvases this canvas is displayed within as dirty + BOOST_FOREACH(CanvasWeakPtr canvas, _parent_canvases) { if( !canvas.expired() ) canvas.lock()->_render_dirty = true; @@ -267,12 +313,13 @@ } //---------------------------------------------------------------------------- - naRef Canvas::addEventListener(const nasal::CallContext& ctx) + bool Canvas::addEventListener( const std::string& type, + const EventListener& cb ) { if( !_root_group.get() ) - naRuntimeError(ctx.c, "Canvas: No root group!"); + throw std::runtime_error("Canvas::AddEventListener: no root group!"); - return _root_group->addEventListener(ctx); + return _root_group->addEventListener(type, cb); } //---------------------------------------------------------------------------- @@ -344,13 +391,19 @@ //---------------------------------------------------------------------------- int Canvas::getViewWidth() const { - return _view_width; + return _texture.getViewSize().x(); } //---------------------------------------------------------------------------- int Canvas::getViewHeight() const { - return _view_height; + return _texture.getViewSize().y(); + } + + //---------------------------------------------------------------------------- + SGRect Canvas::getViewport() const + { + return SGRect(0, 0, getViewWidth(), getViewHeight()); } //---------------------------------------------------------------------------- @@ -361,7 +414,8 @@ EventVisitor visitor( EventVisitor::TRAVERSE_DOWN, event->getClientPos(), - event->getDelta() ); + event->getDelta(), + _root_group ); if( !_root_group->accept(visitor) ) return false; @@ -408,21 +462,26 @@ if( node->getParent()->getParent() == _node && node->getParent()->getNameString() == "placement" ) { - bool placement_dirty = false; - BOOST_FOREACH(Placements& placements, _placements) + size_t index = node->getIndex(); + if( index < _placements.size() ) { - BOOST_FOREACH(PlacementPtr& placement, placements) + Placements& placements = _placements[index]; + if( !placements.empty() ) { - // check if change can be directly handled by placement - if( placement->getProps() == node->getParent() - && !placement->childChanged(node) ) - placement_dirty = true; + bool placement_dirty = false; + BOOST_FOREACH(PlacementPtr& placement, placements) + { + // check if change can be directly handled by placement + if( placement->getProps() == node->getParent() + && !placement->childChanged(node) ) + placement_dirty = true; + } + + if( !placement_dirty ) + return; } } - if( !placement_dirty ) - return; - // prevent double updates... for( size_t i = 0; i < _dirty_placements.size(); ++i ) { @@ -449,6 +508,10 @@ { _sampling_dirty = true; } + else if( node->getNameString() == "additive-blend" ) + { + _texture.useAdditiveBlend( node->getBoolValue() ); + } else if( node->getNameString() == "render-always" ) { _render_always = node->getBoolValue(); @@ -492,6 +555,24 @@ } //---------------------------------------------------------------------------- + void Canvas::reloadPlacements(const std::string& type) + { + for(size_t i = 0; i < _placements.size(); ++i) + { + if( _placements[i].empty() ) + continue; + + SGPropertyNode* child = _placements[i].front()->getProps(); + if( type.empty() + // reload if type matches or no type specified + || child->getStringValue("type", type.c_str()) == type ) + { + _dirty_placements.push_back(child); + } + } + } + + //---------------------------------------------------------------------------- void Canvas::addPlacementFactory( const std::string& type, PlacementFactory factory ) { @@ -500,13 +581,41 @@ ( SG_GENERAL, SG_WARN, - "Canvas::addPlacementFactory: replace existing factor for type " << type + "Canvas::addPlacementFactory: replace existing factory '" << type << "'" ); _placement_factories[type] = factory; } //---------------------------------------------------------------------------- + void Canvas::removePlacementFactory(const std::string& type) + { + PlacementFactoryMap::iterator it = _placement_factories.find(type); + if( it == _placement_factories.end() ) + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "Canvas::removePlacementFactory: no such factory '" << type << "'" + ); + else + _placement_factories.erase(it); + } + + + //---------------------------------------------------------------------------- + void Canvas::setSystemAdapter(const SystemAdapterPtr& system_adapter) + { + _system_adapter = system_adapter; + } + + //---------------------------------------------------------------------------- + SystemAdapterPtr Canvas::getSystemAdapter() + { + return _system_adapter; + } + + //---------------------------------------------------------------------------- void Canvas::setSelf(const PropertyBasedElementPtr& self) { PropertyBasedElement::setSelf(self); @@ -547,6 +656,7 @@ //---------------------------------------------------------------------------- Canvas::PlacementFactoryMap Canvas::_placement_factories; + SystemAdapterPtr Canvas::_system_adapter; } // namespace canvas } // namespace simgear diff -Nru simgear-2.10.0/simgear/canvas/CanvasEvent.cxx simgear-3.0.0/simgear/canvas/CanvasEvent.cxx --- simgear-2.10.0/simgear/canvas/CanvasEvent.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasEvent.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -63,6 +63,12 @@ } //---------------------------------------------------------------------------- + ElementWeakPtr Event::getCurrentTarget() const + { + return current_target; + } + + //---------------------------------------------------------------------------- double Event::getTime() const { return time; diff -Nru simgear-2.10.0/simgear/canvas/CanvasEvent.hxx simgear-3.0.0/simgear/canvas/CanvasEvent.hxx --- simgear-2.10.0/simgear/canvas/CanvasEvent.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasEvent.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -41,7 +41,8 @@ }; Type type; - ElementWeakPtr target; + ElementWeakPtr target, + current_target; double time; bool propagation_stopped; @@ -55,6 +56,7 @@ std::string getTypeString() const; ElementWeakPtr getTarget() const; + ElementWeakPtr getCurrentTarget() const; double getTime() const; diff -Nru simgear-2.10.0/simgear/canvas/CanvasEventListener.cxx simgear-3.0.0/simgear/canvas/CanvasEventListener.cxx --- simgear-2.10.0/simgear/canvas/CanvasEventListener.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasEventListener.cxx 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -// Listener for canvas (GUI) events being passed to a Nasal function/code -// -// Copyright (C) 2012 Thomas Geymayer -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - -#include "CanvasEvent.hxx" -#include "CanvasEventListener.hxx" -#include "CanvasSystemAdapter.hxx" - -#include - -namespace simgear -{ -namespace canvas -{ - - //---------------------------------------------------------------------------- - EventListener::EventListener(naRef code, const SystemAdapterPtr& sys_adapter): - _code(code), - _gc_key(-1), - _sys(sys_adapter) - { - assert( sys_adapter ); - if( !naIsCode(code) - && !naIsCCode(code) - && !naIsFunc(code) ) - throw std::runtime_error - ( - "canvas::EventListener: invalid function argument" - ); - - _gc_key = sys_adapter->gcSave(_code); - } - - //---------------------------------------------------------------------------- - EventListener::~EventListener() - { - assert( !_sys.expired() ); - _sys.lock()->gcRelease(_gc_key); - } - - //---------------------------------------------------------------------------- - void EventListener::call(const canvas::EventPtr& event) - { - SystemAdapterPtr sys = _sys.lock(); - - naRef args[] = { - nasal::Ghost::create(sys->getNasalContext(), event) - }; - const int num_args = sizeof(args)/sizeof(args[0]); - - sys->callMethod(_code, naNil(), num_args, args, naNil()); - } - - -} // namespace canvas -} // namespace simgear diff -Nru simgear-2.10.0/simgear/canvas/CanvasEventListener.hxx simgear-3.0.0/simgear/canvas/CanvasEventListener.hxx --- simgear-2.10.0/simgear/canvas/CanvasEventListener.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasEventListener.hxx 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -// Listener for canvas (GUI) events being passed to a Nasal function/code -// -// Copyright (C) 2012 Thomas Geymayer -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - -#ifndef CANVAS_EVENT_LISTENER_HXX_ -#define CANVAS_EVENT_LISTENER_HXX_ - -#include "canvas_fwd.hxx" -#include - -namespace simgear -{ -namespace canvas -{ - - class EventListener - { - public: - EventListener( naRef code, - const SystemAdapterPtr& sys_adapter ); - ~EventListener(); - - void call(const canvas::EventPtr& event); - - protected: - naRef _code; - int _gc_key; - SystemAdapterWeakPtr _sys; - }; - -} // namespace canvas -} // namespace simgear - -#endif /* CANVAS_EVENT_LISTENER_HXX_ */ diff -Nru simgear-2.10.0/simgear/canvas/CanvasEventManager.cxx simgear-3.0.0/simgear/canvas/CanvasEventManager.cxx --- simgear-2.10.0/simgear/canvas/CanvasEventManager.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasEventManager.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -19,6 +19,7 @@ #include "CanvasEventManager.hxx" #include "MouseEvent.hxx" #include +#include namespace simgear { @@ -71,6 +72,7 @@ bool EventManager::handleEvent( const MouseEventPtr& event, const EventPropagationPath& path ) { + bool handled = false; switch( event->type ) { case Event::MOUSE_DOWN: @@ -78,20 +80,27 @@ break; case Event::MOUSE_UP: { - if( _last_mouse_down.path.empty() ) - // Ignore mouse up without any previous mouse down - return false; + // If the mouse has moved while a button was down (aka. dragging) we + // need to notify the original element that the mouse has left it, and + // the new element that it has been entered + if( _last_mouse_down.path != path ) + handled |= handleMove(event, path); // normal mouseup - propagateEvent(event, path); + handled |= propagateEvent(event, path); + + if( _last_mouse_down.path.empty() ) + // Ignore mouse up without any previous mouse down + return handled; // now handle click/dblclick if( checkClickDistance(path, _last_mouse_down.path) ) - handleClick(event, getCommonAncestor(_last_mouse_down.path, path)); + handled |= + handleClick(event, getCommonAncestor(_last_mouse_down.path, path)); _last_mouse_down.clear(); - return true; + return handled; } case Event::DRAG: if( !_last_mouse_down.valid() ) @@ -99,11 +108,18 @@ else return propagateEvent(event, _last_mouse_down.path); case Event::MOUSE_MOVE: - handleMove(event, path); + handled |= handleMove(event, path); break; case Event::MOUSE_LEAVE: // Mouse leaves window and therefore also current mouseover element handleMove(event, EventPropagationPath()); + + // Event is only send if mouse is moved outside the window or dragging + // has ended somewhere outside the window. In both cases a mouse button + // has been released, so no more mouse down or click... + _last_mouse_down.clear(); + _last_click.clear(); + return true; case Event::WHEEL: break; @@ -111,11 +127,11 @@ return false; } - return propagateEvent(event, path); + return handled | propagateEvent(event, path); } //---------------------------------------------------------------------------- - void EventManager::handleClick( const MouseEventPtr& event, + bool EventManager::handleClick( const MouseEventPtr& event, const EventPropagationPath& path ) { MouseEventPtr click(new MouseEvent(*event)); @@ -145,36 +161,76 @@ dbl_click->type = Event::DBL_CLICK; } - propagateEvent(click, path); + bool handled = propagateEvent(click, path); if( dbl_click ) - propagateEvent(dbl_click, getCommonAncestor(_last_click.path, path)); + handled |= propagateEvent( dbl_click, + getCommonAncestor(_last_click.path, path) ); _last_click = StampedPropagationPath(path, event->getTime()); + + return handled; } //---------------------------------------------------------------------------- - void EventManager::handleMove( const MouseEventPtr& event, + bool EventManager::handleMove( const MouseEventPtr& event, const EventPropagationPath& path ) { - if( _last_mouse_over.path == path ) - return; + EventPropagationPath& last_path = _last_mouse_over.path; + if( last_path == path ) + return false; + + bool handled = false; - if( !_last_mouse_over.path.empty() ) + // Leave old element + if( !last_path.empty() ) { MouseEventPtr mouseout(new MouseEvent(*event)); mouseout->type = Event::MOUSE_OUT; - propagateEvent(mouseout, _last_mouse_over.path); + handled |= propagateEvent(mouseout, last_path); + + // Send a mouseleave event to all ancestors of the currently left element + // which are not ancestor of the new element currently entered + EventPropagationPath path_leave = last_path; + for(size_t i = path_leave.size() - 1; i > 0; --i) + { + if( i < path.size() && path[i] == path_leave[i] ) + break; + + MouseEventPtr mouseleave(new MouseEvent(*event)); + mouseleave->type = Event::MOUSE_LEAVE; + handled |= propagateEvent(mouseleave, path_leave); + + path_leave.pop_back(); + } } + // Enter new element if( !path.empty() ) { MouseEventPtr mouseover(new MouseEvent(*event)); mouseover->type = Event::MOUSE_OVER; - propagateEvent(mouseover, path); + handled |= propagateEvent(mouseover, path); + + // Send a mouseenter event to all ancestors of the currently entered + // element which are not ancestor of the old element currently being + // left + EventPropagationPath path_enter; + for(size_t i = 0; i < path.size(); ++i) + { + path_enter.push_back(path[i]); + + if( i < last_path.size() && path[i] == last_path[i] ) + continue; + + MouseEventPtr mouseenter(new MouseEvent(*event)); + mouseenter->type = Event::MOUSE_ENTER; + handled |= propagateEvent(mouseenter, path_enter); + } } _last_mouse_over.path = path; + return handled; } //---------------------------------------------------------------------------- @@ -188,15 +244,29 @@ // http://www.w3.org/TR/DOM-Level-3-Events/#event-flow // Capturing phase -// for( EventTargets::iterator it = _target_path.begin(); -// it != _target_path.end(); -// ++it ) +// for( EventPropagationPath::const_iterator it = path.begin(); +// it != path.end(); +// ++it ) // { -// if( it->element ) -// std::cout << it->element->getProps()->getPath() << " " -// << "(" << it->local_pos.x() << "|" << it->local_pos.y() << ")\n"; +// if( !it->element.expired() ) +// std::cout << it->element.lock()->getProps()->getPath() << std::endl; // } + // Check if event supports bubbling + const Event::Type types_no_bubbling[] = { + Event::MOUSE_ENTER, + Event::MOUSE_LEAVE, + }; + const size_t num_types_no_bubbling = sizeof(types_no_bubbling) + / sizeof(types_no_bubbling[0]); + bool do_bubble = true; + for( size_t i = 0; i < num_types_no_bubbling; ++i ) + if( event->type == types_no_bubbling[i] ) + { + do_bubble = false; + break; + } + // Bubbling phase for( EventPropagationPath::const_reverse_iterator it = path.rbegin(); @@ -206,29 +276,34 @@ ElementPtr el = it->element.lock(); if( !el ) + { // Ignore element if it has been destroyed while traversing the event // (eg. removed by another event handler) - continue; + if( do_bubble ) + continue; + else + break; + } - // TODO provide functions to convert position and delta to local - // coordinates on demand. Events shouldn't contain informations in - // local coordinates as they might differe between different elements - // receiving the same event. -// if( mouse_event && event->type != Event::DRAG ) -// { -// // TODO transform pos and delta for drag events. Maybe we should just -// // store the global coordinates and convert to local coordinates -// // on demand. -// -// // Position and delta are specified in local coordinate system of -// // current element -// mouse_event->pos = it->local_pos; -// mouse_event->delta = it->local_delta; -// } + // TODO provide functions to convert delta to local coordinates on demand. + // Maybe also provide a clone method for events as local coordinates + // might differ between different elements receiving the same event. + if( mouse_event ) //&& event->type != Event::DRAG ) + { + // TODO transform pos and delta for drag events. Maybe we should just + // store the global coordinates and convert to local coordinates + // on demand. + + // Position and delta are specified in local coordinate system of + // current element + mouse_event->local_pos = it->local_pos; + //mouse_event->delta = it->local_delta; + } - el->callListeners(event); + event->current_target = el; + el->handleEvent(event); - if( event->propagation_stopped ) + if( event->propagation_stopped || !do_bubble ) return true; } @@ -241,8 +316,8 @@ const EventPropagationPath& path2 ) const { osg::Vec2 delta = path1.front().local_pos - path2.front().local_pos; - return delta.x() < drag_threshold - && delta.y() < drag_threshold; + return std::fabs(delta.x()) < drag_threshold + && std::fabs(delta.y()) < drag_threshold; } //---------------------------------------------------------------------------- @@ -250,6 +325,9 @@ EventManager::getCommonAncestor( const EventPropagationPath& path1, const EventPropagationPath& path2 ) const { + if( path1.empty() || path2.empty() ) + return EventPropagationPath(); + if( path1.back().element.lock() == path2.back().element.lock() ) return path2; diff -Nru simgear-2.10.0/simgear/canvas/CanvasEventManager.hxx simgear-3.0.0/simgear/canvas/CanvasEventManager.hxx --- simgear-2.10.0/simgear/canvas/CanvasEventManager.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasEventManager.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -70,13 +70,13 @@ /** * Propagate click event and handle multi-click (eg. create dblclick) */ - void handleClick( const MouseEventPtr& event, + bool handleClick( const MouseEventPtr& event, const EventPropagationPath& path ); /** * Handle mouseover/enter/out/leave */ - void handleMove( const MouseEventPtr& event, + bool handleMove( const MouseEventPtr& event, const EventPropagationPath& path ); bool propagateEvent( const EventPtr& event, diff -Nru simgear-2.10.0/simgear/canvas/CanvasEventVisitor.cxx simgear-3.0.0/simgear/canvas/CanvasEventVisitor.cxx --- simgear-2.10.0/simgear/canvas/CanvasEventVisitor.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasEventVisitor.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -30,8 +30,10 @@ //---------------------------------------------------------------------------- EventVisitor::EventVisitor( TraverseMode mode, const osg::Vec2f& pos, - const osg::Vec2f& delta ): - _traverse_mode( mode ) + const osg::Vec2f& delta, + const ElementPtr& root ): + _traverse_mode( mode ), + _root(root) { if( mode == TRAVERSE_DOWN ) { @@ -70,10 +72,11 @@ m(0, 1) * pos[0] + m(1, 1) * pos[1] + m(3, 1) ); - // Don't check collision with root element (2nd element in _target_path) - // do event listeners attached to the canvas itself (its root group) - // always get called even if no element has been hit. - if( _target_path.size() > 2 && !el.hitBound(pos, local_pos) ) + // Don't check specified root element for collision, as its purpose is to + // catch all events which have no target. This allows for example calling + // event listeners attached to the canvas itself (its root group) even if + // no element has been hit. + if( _root.get() != &el && !el.hitBound(pos, local_pos) ) return false; const osg::Vec2f& delta = _target_path.back().local_delta; @@ -86,7 +89,7 @@ EventTarget target = {el.getWeakPtr(), local_pos, local_delta}; _target_path.push_back(target); - if( el.traverse(*this) || _target_path.size() <= 2 ) + if( el.traverse(*this) || &el == _root.get() ) return true; _target_path.pop_back(); diff -Nru simgear-2.10.0/simgear/canvas/CanvasEventVisitor.hxx simgear-3.0.0/simgear/canvas/CanvasEventVisitor.hxx --- simgear-2.10.0/simgear/canvas/CanvasEventVisitor.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasEventVisitor.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -38,9 +38,17 @@ TRAVERSE_DOWN }; + /** + * + * @param mode + * @param pos Mouse position + * @param delta Mouse movement since last mouse move event + * @param root Element to dispatch events to if no element is hit + */ EventVisitor( TraverseMode mode, const osg::Vec2f& pos, - const osg::Vec2f& delta ); + const osg::Vec2f& delta, + const ElementPtr& root = ElementPtr() ); virtual ~EventVisitor(); virtual bool traverse(Element& el); virtual bool apply(Element& el); @@ -51,6 +59,7 @@ TraverseMode _traverse_mode; EventPropagationPath _target_path; + ElementPtr _root; }; diff -Nru simgear-2.10.0/simgear/canvas/canvas_fwd.hxx simgear-3.0.0/simgear/canvas/canvas_fwd.hxx --- simgear-2.10.0/simgear/canvas/canvas_fwd.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/canvas_fwd.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -51,7 +51,6 @@ SG_FWD_DECL(Text) SG_FWD_DECL(Event) - SG_FWD_DECL(EventListener) SG_FWD_DECL(MouseEvent) SG_FWD_DECL(Placement) SG_FWD_DECL(SystemAdapter) @@ -73,6 +72,8 @@ typedef boost::function PlacementFactory; + typedef boost::function EventListener; + } // namespace canvas } // namespace simgear diff -Nru simgear-2.10.0/simgear/canvas/Canvas.hxx simgear-3.0.0/simgear/canvas/Canvas.hxx --- simgear-2.10.0/simgear/canvas/Canvas.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/Canvas.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -23,12 +23,13 @@ #include "ODGauge.hxx" #include +#include #include #include #include #include -#include +#include #include namespace simgear @@ -71,30 +72,55 @@ Canvas(SGPropertyNode* node); virtual ~Canvas(); - - void setSystemAdapter(const SystemAdapterPtr& system_adapter); - SystemAdapterPtr getSystemAdapter() const; + virtual void onDestroy(); void setCanvasMgr(CanvasMgr* canvas_mgr); CanvasMgr* getCanvasMgr() const; + bool isInit() const; + /** - * Add a canvas which should be mared as dirty upon any change to this + * Add a canvas which should be marked as dirty upon any change to this * canvas. * * This mechanism is used to eg. redraw a canvas if it's displaying * another canvas (recursive canvases) */ - void addDependentCanvas(const CanvasWeakPtr& canvas); + void addParentCanvas(const CanvasWeakPtr& canvas); + + /** + * Add a canvas which should be marked visible if this canvas is visible. + */ + void addChildCanvas(const CanvasWeakPtr& canvas); /** * Stop notifying the given canvas upon changes */ - void removeDependentCanvas(const CanvasWeakPtr& canvas); + void removeParentCanvas(const CanvasWeakPtr& canvas); + void removeChildCanvas(const CanvasWeakPtr& canvas); + /** + * Create a new group + */ GroupPtr createGroup(const std::string& name = ""); /** + * Get an existing group with the given name + */ + GroupPtr getGroup(const std::string& name); + + /** + * Get an existing group with the given name or otherwise create a new + * group + */ + GroupPtr getOrCreateGroup(const std::string& name); + + /** + * Get the root group of the canvas + */ + GroupPtr getRootGroup(); + + /** * Enable rendering for the next frame * * @param force Force redraw even if nothing has changed (if dirty flag @@ -104,7 +130,7 @@ void update(double delta_time_sec); - naRef addEventListener(const nasal::CallContext& ctx); + bool addEventListener(const std::string& type, const EventListener& cb); void setSizeX(int sx); void setSizeY(int sy); @@ -117,6 +143,7 @@ int getViewWidth() const; int getViewHeight() const; + SGRect getViewport() const; bool handleMouseEvent(const MouseEventPtr& event); @@ -130,15 +157,26 @@ CullCallbackPtr getCullCallback() const; + void reloadPlacements( const std::string& type = std::string() ); static void addPlacementFactory( const std::string& type, PlacementFactory factory ); + static void removePlacementFactory(const std::string& type); + + /** + * Set global SystemAdapter for all Canvas/ODGauge instances. + * + * The SystemAdapter is responsible for application specific operations + * like loading images/fonts and adding/removing cameras to the scene + * graph. + */ + static void setSystemAdapter(const SystemAdapterPtr& system_adapter); + static SystemAdapterPtr getSystemAdapter(); protected: - SystemAdapterPtr _system_adapter; CanvasMgr *_canvas_mgr; - std::auto_ptr _event_manager; + boost::scoped_ptr _event_manager; int _size_x, _size_y, @@ -160,9 +198,9 @@ std::vector _dirty_placements; std::vector _placements; - std::set _dependent_canvases; // _parent_canvases, // PlacementFactoryMap; static PlacementFactoryMap _placement_factories; @@ -172,6 +210,8 @@ private: + static SystemAdapterPtr _system_adapter; + Canvas(const Canvas&); // = delete; Canvas& operator=(const Canvas&); // = delete; }; diff -Nru simgear-2.10.0/simgear/canvas/CanvasMgr.cxx simgear-3.0.0/simgear/canvas/CanvasMgr.cxx --- simgear-2.10.0/simgear/canvas/CanvasMgr.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasMgr.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -18,6 +18,7 @@ #include "CanvasMgr.hxx" #include "Canvas.hxx" +#include "CanvasEventManager.hxx" #include @@ -35,10 +36,8 @@ } //---------------------------------------------------------------------------- - CanvasMgr::CanvasMgr( SGPropertyNode_ptr node, - SystemAdapterPtr system_adapter ): - PropertyBasedMgr(node, "texture", &canvasFactory), - _system_adapter(system_adapter) + CanvasMgr::CanvasMgr(SGPropertyNode_ptr node): + PropertyBasedMgr(node, "texture", &canvasFactory) { } @@ -65,7 +64,6 @@ void CanvasMgr::elementCreated(PropertyBasedElementPtr element) { CanvasPtr canvas = boost::static_pointer_cast(element); - canvas->setSystemAdapter(_system_adapter); canvas->setCanvasMgr(this); } diff -Nru simgear-2.10.0/simgear/canvas/CanvasMgr.hxx simgear-3.0.0/simgear/canvas/CanvasMgr.hxx --- simgear-2.10.0/simgear/canvas/CanvasMgr.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasMgr.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -34,12 +34,8 @@ /** * @param node Root node of branch used to control canvasses - * @param system_adapter Adapter for connecting between canvas and - * application framework - * */ - CanvasMgr( SGPropertyNode_ptr node, - SystemAdapterPtr system_adapter ); + CanvasMgr(SGPropertyNode_ptr node); /** * Create a new canvas @@ -65,8 +61,6 @@ protected: - SystemAdapterPtr _system_adapter; - virtual void elementCreated(PropertyBasedElementPtr element); }; diff -Nru simgear-2.10.0/simgear/canvas/CanvasObjectPlacement.cxx simgear-3.0.0/simgear/canvas/CanvasObjectPlacement.cxx --- simgear-2.10.0/simgear/canvas/CanvasObjectPlacement.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasObjectPlacement.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,244 @@ +// Canvas placement for placing a canvas texture onto osg objects. +// +// It also provides a SGPickCallback for passing mouse events to the canvas and +// manages emissive lighting of the placed canvas. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "Canvas.hxx" +#include "CanvasObjectPlacement.hxx" +#include "MouseEvent.hxx" + +#include +#include + +#include + +namespace simgear +{ +namespace canvas +{ + + /** + * Handle picking events on object with a canvas placed onto + */ + class ObjectPickCallback: + public SGPickCallback + { + public: + + ObjectPickCallback(const CanvasWeakPtr& canvas): + _canvas(canvas) + {} + + virtual bool needsUV() const { return true; } + + virtual bool buttonPressed( int, + const osgGA::GUIEventAdapter& ea, + const Info& info ) + { + MouseEventPtr event(new MouseEvent(ea)); + updatePosFromUV(event, info.uv); + + if( ea.getEventType() == osgGA::GUIEventAdapter::SCROLL ) + { + event->type = Event::WHEEL; + event->delta.set(0,0); + switch( ea.getScrollingMotion() ) + { + case osgGA::GUIEventAdapter::SCROLL_UP: + event->delta.y() = 1; + break; + case osgGA::GUIEventAdapter::SCROLL_DOWN: + event->delta.y() = -1; + break; + default: + return false; + } + } + else + { + event->type = Event::MOUSE_DOWN; + } + + return handleEvent(event); + } + + virtual void buttonReleased( int, + const osgGA::GUIEventAdapter& ea, + const Info* info ) + { + if( ea.getEventType() != osgGA::GUIEventAdapter::RELEASE ) + return; + + MouseEventPtr event(new MouseEvent(ea)); + event->type = Event::MOUSE_UP; + updatePosFromUV(event, info ? info->uv : SGVec2d(-1,-1)); + + handleEvent(event); + } + + virtual void mouseMoved( const osgGA::GUIEventAdapter& ea, + const Info* info ) + { + // drag (currently only with LMB) + if( ea.getEventType() != osgGA::GUIEventAdapter::DRAG ) + return; + + MouseEventPtr event(new MouseEvent(ea)); + event->type = Event::DRAG; + updatePosFromUV(event, info ? info->uv : SGVec2d(-1,-1)); + + handleEvent(event); + } + + virtual bool hover( const osg::Vec2d& windowPos, + const Info& info ) + { + // TODO somehow get more info about event (time, modifiers, pressed + // buttons, ...) + MouseEventPtr event(new MouseEvent); + event->type = Event::MOUSE_MOVE; + event->screen_pos = windowPos; + updatePosFromUV(event, info.uv); + + return handleEvent(event); + } + + virtual void mouseLeave( const osg::Vec2d& windowPos ) + { + MouseEventPtr event(new MouseEvent); + event->type = Event::MOUSE_LEAVE; + event->screen_pos = windowPos; + + handleEvent(event); + } + + protected: + CanvasWeakPtr _canvas; + osg::Vec2f _last_pos, + _last_delta; + + void updatePosFromUV(const MouseEventPtr& event, const SGVec2d& uv) + { + CanvasPtr canvas = _canvas.lock(); + if( !canvas ) + return; + + osg::Vec2d pos( uv.x() * canvas->getViewWidth(), + (1 - uv.y()) * canvas->getViewHeight() ); + + _last_delta = pos - _last_pos; + _last_pos = pos; + + event->client_pos = pos; + event->delta = _last_delta; + } + + bool handleEvent(const MouseEventPtr& event) + { + CanvasPtr canvas = _canvas.lock(); + if( !canvas ) + return false; + + return canvas->handleMouseEvent(event); + } + }; + + //---------------------------------------------------------------------------- + ObjectPlacement::ObjectPlacement( SGPropertyNode* node, + const GroupPtr& group, + const CanvasWeakPtr& canvas ): + Placement(node), + _group(group), + _canvas(canvas) + { + // TODO make more generic and extendable for more properties + if( node->hasValue("emission") ) + setEmission( node->getFloatValue("emission") ); + if( node->hasValue("capture-events") ) + setCaptureEvents( node->getBoolValue("capture-events") ); + } + + //---------------------------------------------------------------------------- + ObjectPlacement::~ObjectPlacement() + { + assert( _group->getNumChildren() == 1 ); + osg::Node *child = _group->getChild(0); + + if( _group->getNumParents() ) + { + osg::Group *parent = _group->getParent(0); + parent->addChild(child); + parent->removeChild(_group); + } + + _group->removeChild(child); + } + + //---------------------------------------------------------------------------- + void ObjectPlacement::setEmission(float emit) + { + emit = SGMiscf::clip(emit, 0, 1); + + if( !_material ) + { + _material = new osg::Material; + _material->setColorMode(osg::Material::OFF); + _material->setDataVariance(osg::Object::DYNAMIC); + _group->getOrCreateStateSet() + ->setAttribute(_material, ( osg::StateAttribute::ON + | osg::StateAttribute::OVERRIDE ) ); + } + + _material->setEmission( + osg::Material::FRONT_AND_BACK, + osg::Vec4(emit, emit, emit, emit) + ); + } + + //---------------------------------------------------------------------------- + void ObjectPlacement::setCaptureEvents(bool enable) + { + if( !enable && _scene_user_data ) + return; + + if( enable && !_pick_cb ) + _pick_cb = new ObjectPickCallback(_canvas); + + _scene_user_data = SGSceneUserData::getOrCreateSceneUserData(_group); + _scene_user_data->setPickCallback(enable ? _pick_cb.get() : 0); + } + + //---------------------------------------------------------------------------- + bool ObjectPlacement::childChanged(SGPropertyNode* node) + { + if( node->getParent() != _node ) + return false; + + if( node->getNameString() == "emission" ) + setEmission( node->getFloatValue() ); + else if( node->getNameString() == "capture-events" ) + setCaptureEvents( node->getBoolValue() ); + else + return false; + + return true; + } + +} // namespace canvas +} // namespace simgear diff -Nru simgear-2.10.0/simgear/canvas/CanvasObjectPlacement.hxx simgear-3.0.0/simgear/canvas/CanvasObjectPlacement.hxx --- simgear-2.10.0/simgear/canvas/CanvasObjectPlacement.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasObjectPlacement.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,75 @@ +// Canvas placement for placing a canvas texture onto osg objects. +// +// It also provides a SGPickCallback for passing mouse events to the canvas and +// manages emissive lighting of the placed canvas. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef CANVAS_PICK_PLACEMENT_HXX_ +#define CANVAS_OBJECT_PLACEMENT_HXX_ + +#include "CanvasPlacement.hxx" +#include "canvas_fwd.hxx" + +#include +#include + +namespace simgear +{ +namespace canvas +{ + + class ObjectPlacement: + public Placement + { + public: + + typedef osg::ref_ptr GroupPtr; + typedef osg::ref_ptr MaterialPtr; + + ObjectPlacement( SGPropertyNode* node, + const GroupPtr& group, + const CanvasWeakPtr& canvas ); + virtual ~ObjectPlacement(); + + /** + * Set emissive lighting of the object the canvas is placed on. + */ + void setEmission(float emit); + + /** + * Set whether pick events should be captured. + */ + void setCaptureEvents(bool enable); + + virtual bool childChanged(SGPropertyNode* child); + + protected: + typedef SGSharedPtr PickCallbackPtr; + typedef osg::ref_ptr SGSceneUserDataPtr; + + GroupPtr _group; + MaterialPtr _material; + CanvasWeakPtr _canvas; + PickCallbackPtr _pick_cb; + SGSceneUserDataPtr _scene_user_data; + }; + +} // namespace canvas +} // namespace simgear + +#endif /* CANVAS_PICK_PLACEMENT_HXX_ */ diff -Nru simgear-2.10.0/simgear/canvas/CanvasSystemAdapter.hxx simgear-3.0.0/simgear/canvas/CanvasSystemAdapter.hxx --- simgear-2.10.0/simgear/canvas/CanvasSystemAdapter.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CanvasSystemAdapter.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -20,7 +20,6 @@ #define SG_CANVAS_SYSTEM_ADAPTER_HXX_ #include "canvas_fwd.hxx" -#include namespace simgear { @@ -36,29 +35,6 @@ virtual void addCamera(osg::Camera* camera) const = 0; virtual void removeCamera(osg::Camera* camera) const = 0; virtual osg::Image* getImage(const std::string& path) const = 0; - - virtual naContext getNasalContext() const = 0; - - /** - * Save passed reference to Nasal object from being deleted by the - * garbage collector. - */ - virtual int gcSave(naRef r) = 0; - - /** - * Release an object previously passed to ::gcSave to allow it being - * cleaned up by the garbage collector. - */ - virtual void gcRelease(int key) = 0; - - /** - * Call a Nasal function with the given environment and arguments. - */ - virtual naRef callMethod( naRef code, - naRef self, - int argc, - naRef* args, - naRef locals ) = 0; }; } // namespace canvas diff -Nru simgear-2.10.0/simgear/canvas/CMakeLists.txt simgear-3.0.0/simgear/canvas/CMakeLists.txt --- simgear-2.10.0/simgear/canvas/CMakeLists.txt 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -4,11 +4,11 @@ canvas_fwd.hxx Canvas.hxx CanvasEvent.hxx - CanvasEventListener.hxx CanvasEventManager.hxx CanvasEventTypes.hxx CanvasEventVisitor.hxx CanvasMgr.hxx + CanvasObjectPlacement.hxx CanvasPlacement.hxx CanvasSystemAdapter.hxx MouseEvent.hxx @@ -19,10 +19,10 @@ set(SOURCES Canvas.cxx CanvasEvent.cxx - CanvasEventListener.cxx CanvasEventManager.cxx CanvasEventVisitor.cxx CanvasMgr.cxx + CanvasObjectPlacement.cxx CanvasPlacement.cxx ODGauge.cxx VGInitOperation.cxx diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasElement.cxx simgear-3.0.0/simgear/canvas/elements/CanvasElement.cxx --- simgear-2.10.0/simgear/canvas/elements/CanvasElement.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasElement.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -17,10 +17,11 @@ // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA #include "CanvasElement.hxx" -#include -#include #include #include +#include +#include +#include #include #include @@ -28,11 +29,10 @@ #include #include -#include #include -#include #include +#include #include namespace simgear @@ -41,20 +41,110 @@ { const std::string NAME_TRANSFORM = "tf"; + /** + * glScissor with coordinates relative to different reference frames. + */ + class Element::RelativeScissor: + public osg::Scissor + { + public: + + ReferenceFrame _coord_reference; + osg::Matrix _parent_inverse; + + RelativeScissor(): + _coord_reference(GLOBAL) + {} + + virtual void apply(osg::State& state) const + { + const osg::Viewport* vp = state.getCurrentViewport(); + float w2 = 0.5 * vp->width(), + h2 = 0.5 * vp->height(); + + osg::Matrix model_view + ( + w2, 0, 0, 0, + 0, h2, 0, 0, + 0, 0, 1, 0, + w2, h2, 0, 1 + ); + model_view.preMult(state.getProjectionMatrix()); + + if( _coord_reference != GLOBAL ) + { + model_view.preMult(state.getModelViewMatrix()); + + if( _coord_reference == PARENT ) + model_view.preMult(_parent_inverse); + } + + const osg::Vec2 scale( model_view(0,0), model_view(1,1)), + offset(model_view(3,0), model_view(3,1)); + + // TODO check/warn for rotation? + + GLint x = SGMiscf::roundToInt(scale.x() * _x + offset.x()), + y = SGMiscf::roundToInt(scale.y() * _y + offset.y()), + w = SGMiscf::roundToInt(std::fabs(scale.x()) * _width), + h = SGMiscf::roundToInt(std::fabs(scale.y()) * _height); + + if( scale.x() < 0 ) + x -= w; + if( scale.y() < 0 ) + y -= h; + + glScissor(x, y, w, h); + } + }; + //---------------------------------------------------------------------------- - void Element::removeListener() + Element::OSGUserData::OSGUserData(ElementPtr element): + element(element) { - _node->removeChangeListener(this); + } //---------------------------------------------------------------------------- Element::~Element() { - removeListener(); + if( !_transform.valid() ) + return; + + for(unsigned int i = 0; i < _transform->getNumChildren(); ++i) + { + OSGUserData* ud = + static_cast(_transform->getChild(i)->getUserData()); + + if( ud ) + // Ensure parent is cleared to prevent accessing released memory if an + // element somehow survives longer than his parent. + ud->element->_parent = 0; + } + } + + //---------------------------------------------------------------------------- + void Element::setSelf(const PropertyBasedElementPtr& self) + { + PropertyBasedElement::setSelf(self); + _transform->setUserData + ( + new OSGUserData(boost::static_pointer_cast(self)) + ); + } + + //---------------------------------------------------------------------------- + void Element::onDestroy() + { + if( !_transform.valid() ) + return; + + // The transform node keeps a reference on this element, so ensure it is + // deleted. BOOST_FOREACH(osg::Group* parent, _transform->getParents()) { - parent->removeChild(_transform); + parent->removeChild(_transform.get()); } } @@ -65,104 +155,85 @@ } //---------------------------------------------------------------------------- + ElementPtr Element::getParent() + { + return _parent ? _parent->getWeakPtr().lock() : ElementPtr(); + } + + //---------------------------------------------------------------------------- void Element::update(double dt) { if( !_transform->getNodeMask() ) // Don't do anything if element is hidden return; - if( _transform_dirty ) + // Trigger matrix update + getMatrix(); + + if( _attributes_dirty & SCISSOR_COORDS ) { - osg::Matrix m; - for( size_t i = 0; i < _transform_types.size(); ++i ) - { - // Skip unused indizes... - if( _transform_types[i] == TT_NONE ) - continue; - - SGPropertyNode* tf_node = _node->getChild("tf", i, true); - - // Build up the matrix representation of the current transform node - osg::Matrix tf; - switch( _transform_types[i] ) - { - case TT_MATRIX: - tf = osg::Matrix( tf_node->getDoubleValue("m[0]", 1), - tf_node->getDoubleValue("m[1]", 0), - 0, - tf_node->getDoubleValue("m[6]", 0), - - tf_node->getDoubleValue("m[2]", 0), - tf_node->getDoubleValue("m[3]", 1), - 0, - tf_node->getDoubleValue("m[7]", 0), - - 0, - 0, - 1, - 0, - - tf_node->getDoubleValue("m[4]", 0), - tf_node->getDoubleValue("m[5]", 0), - 0, - tf_node->getDoubleValue("m[8]", 1) ); - break; - case TT_TRANSLATE: - tf.makeTranslate( osg::Vec3f( tf_node->getDoubleValue("t[0]", 0), - tf_node->getDoubleValue("t[1]", 0), - 0 ) ); - break; - case TT_ROTATE: - tf.makeRotate( tf_node->getDoubleValue("rot", 0), 0, 0, 1 ); - break; - case TT_SCALE: - { - float sx = tf_node->getDoubleValue("s[0]", 1); - // sy defaults to sx... - tf.makeScale( sx, tf_node->getDoubleValue("s[1]", sx), 1 ); - break; - } - default: - break; - } - m.postMult( tf ); - } - _transform->setMatrix(m); - _transform_dirty = false; + if( _scissor && _scissor->_coord_reference != GLOBAL ) + _scissor->_parent_inverse = _transform->getInverseMatrix(); + + _attributes_dirty &= ~SCISSOR_COORDS; + } + + // Update bounding box on manual update (manual updates pass zero dt) + if( dt == 0 && _drawable ) + _drawable->getBound(); + + if( _attributes_dirty & BLEND_FUNC ) + { + parseBlendFunc( + _transform->getOrCreateStateSet(), + _node->getChild("blend-source"), + _node->getChild("blend-destination"), + _node->getChild("blend-source-rgb"), + _node->getChild("blend-destination-rgb"), + _node->getChild("blend-source-alpha"), + _node->getChild("blend-destination-alpha") + ); + _attributes_dirty &= ~BLEND_FUNC; } } //---------------------------------------------------------------------------- - naRef Element::addEventListener(const nasal::CallContext& ctx) + bool Element::addEventListener( const std::string& type_str, + const EventListener& cb ) { - const std::string type_str = ctx.requireArg(0); - naRef code = ctx.requireArg(1); - SG_LOG ( - SG_NASAL, + SG_GENERAL, SG_INFO, "addEventListener(" << _node->getPath() << ", " << type_str << ")" ); Event::Type type = Event::strToType(type_str); if( type == Event::UNKNOWN ) - naRuntimeError( ctx.c, - "addEventListener: Unknown event type %s", - type_str.c_str() ); + { + SG_LOG( SG_GENERAL, + SG_WARN, + "addEventListener: Unknown event type " << type_str ); + return false; + } - _listener[ type ].push_back - ( - boost::make_shared( code, - _canvas.lock()->getSystemAdapter() ) - ); + _listener[ type ].push_back(cb); - return naNil(); + return true; + } + + //---------------------------------------------------------------------------- + void Element::clearEventListener() + { + _listener.clear(); } //---------------------------------------------------------------------------- bool Element::accept(EventVisitor& visitor) { + if( !isVisible() ) + return false; + return visitor.apply(*this); } @@ -181,14 +252,16 @@ } //---------------------------------------------------------------------------- - void Element::callListeners(const canvas::EventPtr& event) + bool Element::handleEvent(canvas::EventPtr event) { ListenerMap::iterator listeners = _listener.find(event->getType()); if( listeners == _listener.end() ) - return; + return false; + + BOOST_FOREACH(EventListener const& listener, listeners->second) + listener(event); - BOOST_FOREACH(EventListenerPtr listener, listeners->second) - listener->call(event); + return true; } //---------------------------------------------------------------------------- @@ -199,21 +272,28 @@ // Drawables have a bounding box... if( _drawable ) - { - if( !_drawable->getBound().contains(osg::Vec3f(local_pos, 0)) ) - return false; - } + return _drawable->getBound().contains(osg::Vec3f(local_pos, 0)); // ... for other elements, i.e. groups only a bounding sphere is available - else if( !_transform->getBound().contains(osg::Vec3f(pos, 0)) ) - return false; + else + return _transform->getBound().contains(osg::Vec3f(pos, 0)); + } - return true; + //---------------------------------------------------------------------------- + bool Element::isVisible() const + { + return _transform.valid() && _transform->getNodeMask() != 0; + } + + //---------------------------------------------------------------------------- + osg::MatrixTransform* Element::getMatrixTransform() + { + return _transform.get(); } //---------------------------------------------------------------------------- - osg::ref_ptr Element::getMatrixTransform() + osg::MatrixTransform const* Element::getMatrixTransform() const { - return _transform; + return _transform.get(); } //---------------------------------------------------------------------------- @@ -226,7 +306,7 @@ _transform_types.resize( child->getIndex() + 1 ); _transform_types[ child->getIndex() ] = TT_NONE; - _transform_dirty = true; + _attributes_dirty |= TRANSFORM; return; } else if( parent->getParent() == _node @@ -247,7 +327,7 @@ else if( name == "s" ) type = TT_SCALE; - _transform_dirty = true; + _attributes_dirty |= TRANSFORM; return; } @@ -257,26 +337,37 @@ //---------------------------------------------------------------------------- void Element::childRemoved(SGPropertyNode* parent, SGPropertyNode* child) { - if( parent == _node && child->getNameString() == NAME_TRANSFORM ) + if( parent == _node ) { - if( child->getIndex() >= static_cast(_transform_types.size()) ) + if( child->getNameString() == NAME_TRANSFORM ) { - SG_LOG - ( - SG_GENERAL, - SG_WARN, - "Element::childRemoved: unknown transform: " << child->getPath() - ); - return; - } + if( !_transform.valid() ) + return; - _transform_types[ child->getIndex() ] = TT_NONE; + if( child->getIndex() >= static_cast(_transform_types.size()) ) + { + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "Element::childRemoved: unknown transform: " << child->getPath() + ); + return; + } - while( !_transform_types.empty() && _transform_types.back() == TT_NONE ) - _transform_types.pop_back(); + _transform_types[ child->getIndex() ] = TT_NONE; - _transform_dirty = true; - return; + while( !_transform_types.empty() && _transform_types.back() == TT_NONE ) + _transform_types.pop_back(); + + _attributes_dirty |= TRANSFORM; + return; + } + else if( StyleInfo const* style = getStyleInfo(child->getNameString()) ) + { + if( setStyle(getParentStyle(child), style) ) + return; + } } childRemoved(child); @@ -288,18 +379,30 @@ SGPropertyNode *parent = child->getParent(); if( parent == _node ) { - if( setStyle(child) ) + const std::string& name = child->getNameString(); + if( StyleInfo const* style_info = getStyleInfo(name) ) + { + SGPropertyNode const* style = child; + if( isStyleEmpty(child) ) + { + child->clearValue(); + style = getParentStyle(child); + } + setStyle(style, style_info); return; - else if( child->getNameString() == "update" ) + } + else if( name == "update" ) return update(0); - else if( child->getNameString() == "visible" ) + else if( name == "visible" ) // TODO check if we need another nodemask return _transform->setNodeMask( child->getBoolValue() ? 0xffffffff : 0 ); + else if( boost::starts_with(name, "blend-") ) + return (void)(_attributes_dirty |= BLEND_FUNC); } else if( parent->getParent() == _node && parent->getNameString() == NAME_TRANSFORM ) { - _transform_dirty = true; + _attributes_dirty |= TRANSFORM; return; } @@ -307,15 +410,10 @@ } //---------------------------------------------------------------------------- - bool Element::setStyle(const SGPropertyNode* child) + bool Element::setStyle( const SGPropertyNode* child, + const StyleInfo* style_info ) { - StyleSetters::const_iterator setter = - _style_setters.find(child->getNameString()); - if( setter == _style_setters.end() ) - return false; - - setter->second(child); - return true; + return canApplyStyle(child) && setStyleImpl(child, style_info); } //---------------------------------------------------------------------------- @@ -324,6 +422,7 @@ if( clip.empty() || clip == "auto" ) { getOrCreateStateSet()->removeAttribute(osg::StateAttribute::SCISSOR); + _scissor = 0; return; } @@ -336,17 +435,22 @@ return; } - typedef boost::tokenizer > tokenizer; - const boost::char_separator del(", \t\npx"); - - tokenizer tokens(clip.begin() + RECT.size(), clip.end() - 1, del); + const std::string sep(", \t\npx"); int comp = 0; - int values[4]; - for( tokenizer::const_iterator tok = tokens.begin(); - tok != tokens.end() && comp < 4; - ++tok, ++comp ) + float values[4]; + + for(size_t pos = RECT.size(); comp < 4; ++comp) { - values[comp] = boost::lexical_cast(*tok); + pos = clip.find_first_not_of(sep, pos); + if( pos == std::string::npos || pos == clip.size() - 1 ) + break; + + char *end = 0; + values[comp] = strtod(&clip[pos], &end); + if( end == &clip[pos] || !end ) + break; + + pos = end - &clip[0]; } if( comp < 4 ) @@ -355,32 +459,37 @@ return; } - float scale_x = 1, - scale_y = 1; + float width = values[1] - values[3], + height = values[2] - values[0]; - CanvasPtr canvas = _canvas.lock(); - if( canvas ) + if( width < 0 || height < 0 ) { - // The scissor rectangle isn't affected by any transformation, so we need - // to convert to image/canvas coordinates on our selves. - scale_x = canvas->getSizeX() - / static_cast(canvas->getViewWidth()); - scale_y = canvas->getSizeY() - / static_cast(canvas->getViewHeight()); + SG_LOG(SG_GENERAL, SG_WARN, "Canvas: negative clip size: " << clip); + return; } - osg::Scissor* scissor = new osg::Scissor(); + _scissor = new RelativeScissor(); // , , , - scissor->x() = scale_x * values[3]; - scissor->y() = scale_y * values[0]; - scissor->width() = scale_x * (values[1] - values[3]); - scissor->height() = scale_y * (values[2] - values[0]); - - if( canvas ) - // Canvas has y axis upside down - scissor->y() = canvas->getSizeY() - scissor->y() - scissor->height(); + _scissor->x() = SGMiscf::roundToInt(values[3]); + _scissor->y() = SGMiscf::roundToInt(values[0]); + _scissor->width() = SGMiscf::roundToInt(width); + _scissor->height() = SGMiscf::roundToInt(height); + + getOrCreateStateSet()->setAttributeAndModes(_scissor); - getOrCreateStateSet()->setAttributeAndModes(scissor); + SGPropertyNode* clip_frame = _node->getChild("clip-frame", 0); + if( clip_frame ) + valueChanged(clip_frame); + } + + //---------------------------------------------------------------------------- + void Element::setClipFrame(ReferenceFrame rf) + { + if( _scissor ) + { + _scissor->_coord_reference = rf; + _attributes_dirty |= SCISSOR_COORDS; + } } //---------------------------------------------------------------------------- @@ -411,12 +520,82 @@ osg::BoundingBox transformed; const osg::BoundingBox& bb = _drawable->getBound(); for(int i = 0; i < 4; ++i) - transformed.expandBy( m * bb.corner(i) ); + transformed.expandBy( bb.corner(i) * m ); return transformed; } //---------------------------------------------------------------------------- + osg::Matrix Element::getMatrix() const + { + if( !(_attributes_dirty & TRANSFORM) ) + return _transform->getMatrix(); + + osg::Matrix m; + for( size_t i = 0; i < _transform_types.size(); ++i ) + { + // Skip unused indizes... + if( _transform_types[i] == TT_NONE ) + continue; + + SGPropertyNode* tf_node = _node->getChild("tf", i, true); + + // Build up the matrix representation of the current transform node + osg::Matrix tf; + switch( _transform_types[i] ) + { + case TT_MATRIX: + tf = osg::Matrix( tf_node->getDoubleValue("m[0]", 1), + tf_node->getDoubleValue("m[1]", 0), + 0, + tf_node->getDoubleValue("m[6]", 0), + + tf_node->getDoubleValue("m[2]", 0), + tf_node->getDoubleValue("m[3]", 1), + 0, + tf_node->getDoubleValue("m[7]", 0), + + 0, + 0, + 1, + 0, + + tf_node->getDoubleValue("m[4]", 0), + tf_node->getDoubleValue("m[5]", 0), + 0, + tf_node->getDoubleValue("m[8]", 1) ); + break; + case TT_TRANSLATE: + tf.makeTranslate( osg::Vec3f( tf_node->getDoubleValue("t[0]", 0), + tf_node->getDoubleValue("t[1]", 0), + 0 ) ); + break; + case TT_ROTATE: + tf.makeRotate( tf_node->getDoubleValue("rot", 0), 0, 0, 1 ); + break; + case TT_SCALE: + { + float sx = tf_node->getDoubleValue("s[0]", 1); + // sy defaults to sx... + tf.makeScale( sx, tf_node->getDoubleValue("s[1]", sx), 1 ); + break; + } + default: + break; + } + m.postMult( tf ); + } + _transform->setMatrix(m); + _attributes_dirty &= ~TRANSFORM; + _attributes_dirty |= SCISSOR_COORDS; + + return m; + } + + //---------------------------------------------------------------------------- + Element::StyleSetters Element::_style_setters; + + //---------------------------------------------------------------------------- Element::Element( const CanvasWeakPtr& canvas, const SGPropertyNode_ptr& node, const Style& parent_style, @@ -424,11 +603,14 @@ PropertyBasedElement(node), _canvas( canvas ), _parent( parent ), - _transform_dirty( false ), + _attributes_dirty( 0 ), _transform( new osg::MatrixTransform ), _style( parent_style ), + _scissor( 0 ), _drawable( 0 ) { + staticInit(); + SG_LOG ( SG_GL, @@ -436,7 +618,93 @@ "New canvas element " << node->getPath() ); - addStyle("clip", &Element::setClip, this); + // Ensure elements are drawn in order they appear in the element tree + _transform->getOrCreateStateSet() + ->setRenderBinDetails + ( + 0, + "PreOrderBin", + osg::StateSet::OVERRIDE_RENDERBIN_DETAILS + ); + } + + //---------------------------------------------------------------------------- + void Element::staticInit() + { + if( isInit() ) + return; + + addStyle("clip", "", &Element::setClip, false); + addStyle("clip-frame", "", &Element::setClipFrame, false); + } + + //---------------------------------------------------------------------------- + bool Element::isStyleEmpty(const SGPropertyNode* child) const + { + return !child + || simgear::strutils::strip(child->getStringValue()).empty(); + } + + //---------------------------------------------------------------------------- + bool Element::canApplyStyle(const SGPropertyNode* child) const + { + if( _node == child->getParent() ) + return true; + + // Parent values do not override if element has own value + return isStyleEmpty( _node->getChild(child->getName()) ); + } + + //---------------------------------------------------------------------------- + bool Element::setStyleImpl( const SGPropertyNode* child, + const StyleInfo* style_info ) + { + const StyleSetter* style_setter = style_info + ? &style_info->setter + : getStyleSetter(child->getNameString()); + while( style_setter ) + { + if( style_setter->func(*this, child) ) + return true; + style_setter = style_setter->next; + } + return false; + } + + //---------------------------------------------------------------------------- + const Element::StyleInfo* + Element::getStyleInfo(const std::string& name) const + { + StyleSetters::const_iterator setter = _style_setters.find(name); + if( setter == _style_setters.end() ) + return 0; + + return &setter->second; + } + + //---------------------------------------------------------------------------- + const Element::StyleSetter* + Element::getStyleSetter(const std::string& name) const + { + const StyleInfo* info = getStyleInfo(name); + return info ? &info->setter : 0; + } + + //---------------------------------------------------------------------------- + const SGPropertyNode* + Element::getParentStyle(const SGPropertyNode* child) const + { + // Try to get value from parent... + if( _parent ) + { + Style::const_iterator style = + _parent->_style.find(child->getNameString()); + if( style != _parent->_style.end() ) + return style->second; + } + + // ...or reset to default if none is available + return child; // TODO somehow get default value for each style? } //---------------------------------------------------------------------------- diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasElement.hxx simgear-3.0.0/simgear/canvas/elements/CanvasElement.hxx --- simgear-2.10.0/simgear/canvas/elements/CanvasElement.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasElement.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -23,13 +23,13 @@ #include #include #include // for uint32_t -#include #include #include #include #include +#include namespace osg { @@ -45,24 +45,57 @@ public PropertyBasedElement { public: - typedef boost::function StyleSetter; - typedef std::map StyleSetters; /** - * Remove the property listener of the element. - * - * You will need to call the appropriate methods (#childAdded, - * #childRemoved, #valueChanged) yourself to ensure the element still - * receives the needed events. + * Store pointer to window as user data */ - void removeListener(); + class OSGUserData: + public osg::Referenced + { + public: + ElementPtr element; + OSGUserData(ElementPtr element); + }; + + typedef boost::function + StyleSetterFunc; + typedef boost::function + StyleSetterFuncUnchecked; + struct StyleSetter: + public SGReferenced + { + StyleSetterFunc func; + SGSharedPtr next; + }; + struct StyleInfo + { + StyleSetter setter; ///!< Function(s) for setting this style + std::string type; ///!< Interpolation type + bool inheritable; ///!< Whether children can inherit this style from + /// their parents + }; + + /** + * Coordinate reference frame (eg. "clip" property) + */ + enum ReferenceFrame + { + GLOBAL, ///!< Global coordinates + PARENT, ///!< Coordinates relative to parent coordinate frame + LOCAL ///!< Coordinates relative to local coordinates (parent + /// coordinates with local transformations applied) + }; /** * */ virtual ~Element() = 0; + virtual void setSelf(const PropertyBasedElementPtr& self); + virtual void onDestroy(); + ElementWeakPtr getWeakPtr() const; + ElementPtr getParent(); /** * Called every frame to update internal state @@ -71,19 +104,26 @@ */ virtual void update(double dt); - naRef addEventListener(const nasal::CallContext& ctx); + bool addEventListener(const std::string& type, const EventListener& cb); + virtual void clearEventListener(); virtual bool accept(EventVisitor& visitor); virtual bool ascend(EventVisitor& visitor); virtual bool traverse(EventVisitor& visitor); - void callListeners(const canvas::EventPtr& event); + virtual bool handleEvent(canvas::EventPtr event); virtual bool hitBound( const osg::Vec2f& pos, const osg::Vec2f& local_pos ) const; + /** + * Get whether the element is visible or hidden (Can be changed with + * setting property "visible" accordingly). + */ + bool isVisible() const; - osg::ref_ptr getMatrixTransform(); + osg::MatrixTransform* getMatrixTransform(); + osg::MatrixTransform const* getMatrixTransform() const; virtual void childAdded( SGPropertyNode * parent, SGPropertyNode * child ); @@ -91,7 +131,8 @@ SGPropertyNode * child ); virtual void valueChanged(SGPropertyNode * child); - virtual bool setStyle(const SGPropertyNode* child); + virtual bool setStyle( const SGPropertyNode* child, + const StyleInfo* style_info = 0 ); /** * Set clipping shape @@ -102,6 +143,11 @@ void setClip(const std::string& clip); /** + * Clipping coordinates reference frame + */ + void setClipFrame(ReferenceFrame rf); + + /** * Write the given bounding box to the property tree */ void setBoundingBox(const osg::BoundingBox& bb); @@ -111,11 +157,39 @@ */ virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const; + /** + * Get the transformation matrix (product of all transforms) + */ + osg::Matrix getMatrix() const; + + /** + * Create an canvas Element + * + * @tparam Derived Type of element (needs to derive from Element) + */ + template + static + typename boost::enable_if< + boost::is_base_of, + ElementPtr + >::type create( const CanvasWeakPtr& canvas, + const SGPropertyNode_ptr& node, + const Style& style, + Element* parent ) + { + ElementPtr el( new Derived(canvas, node, style, parent) ); + el->setSelf(el); + return el; + } + protected: enum Attributes { - LAST_ATTRIBUTE = 0x0001 + TRANSFORM = 1, + BLEND_FUNC = TRANSFORM << 1, + SCISSOR_COORDS = BLEND_FUNC << 1, + LAST_ATTRIBUTE = SCISSOR_COORDS << 1 }; enum TransformType @@ -127,64 +201,331 @@ TT_SCALE }; + class RelativeScissor; + CanvasWeakPtr _canvas; Element *_parent; - uint32_t _attributes_dirty; + mutable uint32_t _attributes_dirty; - bool _transform_dirty; - osg::ref_ptr _transform; - std::vector _transform_types; + osg::observer_ptr _transform; + std::vector _transform_types; Style _style; - StyleSetters _style_setters; std::vector _bounding_box; + RelativeScissor *_scissor; - typedef std::vector Listener; + typedef std::vector Listener; typedef std::map ListenerMap; ListenerMap _listener; + typedef std::map StyleSetters; + static StyleSetters _style_setters; + + static void staticInit(); + Element( const CanvasWeakPtr& canvas, const SGPropertyNode_ptr& node, const Style& parent_style, Element* parent ); - template - Element::StyleSetter - addStyle(const std::string& name, void (C1::*setter)(T), C2 instance) + /** + * Returns false on first call and true on any successive call. Use to + * perform initialization tasks which are only required once per element + * type. + * + * @tparam Derived (Derived) class type + */ + template + static bool isInit() + { + static bool is_init = false; + if( is_init ) + return true; + + is_init = true; + return false; + } + + /** + * Register a function for setting a style specified by the given property + * + * @param name Property name + * @param type Interpolation type + * @param setter Setter function + * + * @tparam T1 Type of value used to retrieve value from property + * node + * @tparam T2 Type of value the setter function expects + * @tparam Derived Type of class the setter can be applied to + * + * @note T1 needs to be convertible to T2 + */ + template< + typename T1, + typename T2, + class Derived + > + static + StyleSetter + addStyle( const std::string& name, + const std::string& type, + const boost::function& setter, + bool inheritable = true ) + { + StyleInfo& style_info = _style_setters[ name ]; + if( !type.empty() ) + { + if( !style_info.type.empty() && type != style_info.type ) + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "changing animation type for '" << name << "': " + << style_info.type << " -> " << type + ); + + style_info.type = type; + } + // TODO check if changed? + style_info.inheritable = inheritable; + + StyleSetter* style = &style_info.setter; + while( style->next ) + style = style->next; + if( style->func ) + style = style->next = new StyleSetter; + + style->func = boost::bind + ( + &type_match::call, + _1, + _2, + bindStyleSetter(name, setter) + ); + return *style; + } + + template< + typename T, + class Derived + > + static + StyleSetter + addStyle( const std::string& name, + const std::string& type, + const boost::function& setter, + bool inheritable = true ) + { + return addStyle(name, type, setter, inheritable); + } + + template< + typename T, + class Derived + > + static + StyleSetter + addStyle( const std::string& name, + const std::string& type, + void (Derived::*setter)(T), + bool inheritable = true ) + { + return addStyle + ( + name, + type, + boost::function(setter), + inheritable + ); + } + + template< + typename T1, + typename T2, + class Derived + > + static + StyleSetterFunc + addStyle( const std::string& name, + const std::string& type, + void (Derived::*setter)(T2), + bool inheritable = true ) { - return _style_setters[ name ] = - bindStyleSetter(name, setter, instance); + return addStyle + ( + name, + type, + boost::function(setter), + inheritable + ); } - template - Element::StyleSetter - addStyle(const std::string& name, void (C1::*setter)(T2), C2 instance) + template< + class Derived + > + static + StyleSetter + addStyle( const std::string& name, + const std::string& type, + void (Derived::*setter)(const std::string&), + bool inheritable = true ) + { + return addStyle + ( + name, + type, + boost::function(setter), + inheritable + ); + } + + template< + typename T, + class Derived, + class Other, + class OtherRef + > + static + StyleSetter + addStyle( const std::string& name, + const std::string& type, + void (Other::*setter)(T), + OtherRef Derived::*instance_ref, + bool inheritable = true ) + { + return addStyle + ( + name, + type, + bindOther(setter, instance_ref), + inheritable + ); + } + + template< + typename T1, + typename T2, + class Derived, + class Other, + class OtherRef + > + static + StyleSetter + addStyle( const std::string& name, + const std::string& type, + void (Other::*setter)(T2), + OtherRef Derived::*instance_ref, + bool inheritable = true ) + { + return addStyle + ( + name, + type, + bindOther(setter, instance_ref), + inheritable + ); + } + + template< + typename T1, + typename T2, + class Derived, + class Other, + class OtherRef + > + static + StyleSetter + addStyle( const std::string& name, + const std::string& type, + const boost::function& setter, + OtherRef Derived::*instance_ref, + bool inheritable = true ) { - return _style_setters[ name ] = - bindStyleSetter(name, setter, instance); + return addStyle + ( + name, + type, + bindOther(setter, instance_ref), + inheritable + ); } - template - Element::StyleSetter + template< + class Derived, + class Other, + class OtherRef + > + static + StyleSetter addStyle( const std::string& name, - void (C1::*setter)(const std::string&), - C2 instance ) + const std::string& type, + void (Other::*setter)(const std::string&), + OtherRef Derived::*instance_ref, + bool inheritable = true ) { - return _style_setters[ name ] = - bindStyleSetter(name, setter, instance); + return addStyle + ( + name, + type, + boost::function(setter), + instance_ref, + inheritable + ); } - template - Element::StyleSetter + template + static + boost::function + bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref ) + { + return boost::bind(setter, boost::bind(instance_ref, _1), _2); + } + + template + static + boost::function + bindOther( const boost::function& setter, + OtherRef Derived::*instance_ref ) + { + return boost::bind + ( + setter, + boost::bind + ( + &reference_from_pointer, + boost::bind(instance_ref, _1) + ), + _2 + ); + } + + template + static + StyleSetterFuncUnchecked bindStyleSetter( const std::string& name, - void (C1::*setter)(T2), - C2 instance ) + const boost::function& setter ) { - return boost::bind(setter, instance, boost::bind(&getValue, _1)); + return boost::bind + ( + setter, + // We will only call setters with Derived instances, so we can safely + // cast here. + boost::bind(&derived_cast, _1), + boost::bind(&getValue, _2) + ); } + bool isStyleEmpty(const SGPropertyNode* child) const; + bool canApplyStyle(const SGPropertyNode* child) const; + bool setStyleImpl( const SGPropertyNode* child, + const StyleInfo* style_info = 0 ); + + const StyleInfo* getStyleInfo(const std::string& name) const; + const StyleSetter* getStyleSetter(const std::string& name) const; + const SGPropertyNode* getParentStyle(const SGPropertyNode* child) const; + virtual void childAdded(SGPropertyNode * child) {} virtual void childRemoved(SGPropertyNode * child){} virtual void childChanged(SGPropertyNode * child){} @@ -203,9 +544,63 @@ osg::ref_ptr _drawable; Element(const Element&);// = delete + + template + static Derived& derived_cast(Element& el) + { + return static_cast(el); + } + + template + static T& reference_from_pointer(const SharedPtr& p) + { + return *get_pointer(p); + } + + /** + * Helper to call a function only of the element type can be converted to + * the required type. + * + * @return Whether the function has been called + */ + template + struct type_match + { + static bool call( Element& el, + const SGPropertyNode* prop, + const StyleSetterFuncUnchecked& func ) + { + Derived* d = dynamic_cast(&el); + if( !d ) + return false; + func(*d, prop); + return true; + } + }; }; } // namespace canvas + + template<> + struct enum_traits + { + static const char* name() + { + return "canvas::Element::ReferenceFrame"; + } + + static canvas::Element::ReferenceFrame defVal() + { + return canvas::Element::GLOBAL; + } + + static bool validate(int frame) + { + return frame >= canvas::Element::GLOBAL + && frame <= canvas::Element::LOCAL; + } + }; + } // namespace simgear #endif /* CANVAS_ELEMENT_HXX_ */ diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasGroup.cxx simgear-3.0.0/simgear/canvas/elements/CanvasGroup.cxx --- simgear-2.10.0/simgear/canvas/elements/CanvasGroup.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasGroup.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -33,17 +33,37 @@ namespace canvas { /** - * Create an canvas Element of type T + * Add canvas Element type to factory map */ - template - ElementPtr createElement( const CanvasWeakPtr& canvas, - const SGPropertyNode_ptr& node, - const Style& style, - Element* parent ) - { - ElementPtr el( new T(canvas, node, style, parent) ); - el->setSelf(el); - return el; + template + void add(ElementFactories& factories) + { + ElementType::staticInit(); + factories[ElementType::TYPE_NAME] = &Element::create; + } + + //---------------------------------------------------------------------------- + ElementFactories Group::_child_factories; + const std::string Group::TYPE_NAME = "group"; + + void warnTransformExpired(const char* member_name) + { + SG_LOG( SG_GENERAL, + SG_WARN, + "canvas::Group::" << member_name << ": Group has expired." ); + } + + //---------------------------------------------------------------------------- + void Group::staticInit() + { + if( isInit() ) + return; + + add(_child_factories); + add(_child_factories); + add(_child_factories); + add(_child_factories); + add(_child_factories); } //---------------------------------------------------------------------------- @@ -53,11 +73,7 @@ Element* parent ): Element(canvas, node, parent_style, parent) { - _child_factories["group"] = &createElement; - _child_factories["image"] = &createElement; - _child_factories["map" ] = &createElement; - _child_factories["path" ] = &createElement; - _child_factories["text" ] = &createElement; + staticInit(); } //---------------------------------------------------------------------------- @@ -80,22 +96,54 @@ //---------------------------------------------------------------------------- ElementPtr Group::getChild(const SGPropertyNode* node) { - ChildList::iterator child = findChild(node); - if( child == _children.end() ) + return findChild(node, ""); + } + + //---------------------------------------------------------------------------- + ElementPtr Group::getChild(const std::string& id) + { + return findChild(0, id); + } + + //---------------------------------------------------------------------------- + ElementPtr Group::getOrCreateChild( const std::string& type, + const std::string& id ) + { + ElementPtr child = getChild(id); + if( child ) + { + if( child->getProps()->getNameString() == type ) + return child; + + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "Group::getOrCreateChild: type missmatch! " + "('" << type << "' != '" << child->getProps()->getName() << "', " + "id = '" << id << "')" + ); + return ElementPtr(); + } - return child->second; + return createChild(type, id); } //---------------------------------------------------------------------------- ElementPtr Group::getElementById(const std::string& id) { - std::vector groups; + if( !_transform.valid() ) + { + warnTransformExpired("getElementById"); + return ElementPtr(); + } - BOOST_FOREACH( ChildList::value_type child, _children ) + std::vector groups; + for(size_t i = 0; i < _transform->getNumChildren(); ++i) { - const ElementPtr& el = child.second; - if( el->getProps()->getStringValue("id") == id ) + const ElementPtr& el = getChildByIndex(i); + if( el->get("id") == id ) return el; GroupPtr group = boost::dynamic_pointer_cast(el); @@ -114,10 +162,22 @@ } //---------------------------------------------------------------------------- + void Group::clearEventListener() + { + if( !_transform.valid() ) + return warnTransformExpired("clearEventListener"); + + for(size_t i = 0; i < _transform->getNumChildren(); ++i) + getChildByIndex(i)->clearEventListener(); + + Element::clearEventListener(); + } + + //---------------------------------------------------------------------------- void Group::update(double dt) { - BOOST_FOREACH( ChildList::value_type child, _children ) - child.second->update(dt); + for(size_t i = 0; i < _transform->getNumChildren(); ++i) + getChildByIndex(i)->update(dt); Element::update(dt); } @@ -126,30 +186,32 @@ bool Group::traverse(EventVisitor& visitor) { // Iterate in reverse order as last child is displayed on top - BOOST_REVERSE_FOREACH( ChildList::value_type child, _children ) + for(size_t i = _transform->getNumChildren(); i --> 0;) { - if( child.second->accept(visitor) ) + if( getChildByIndex(i)->accept(visitor) ) return true; } return false; } //---------------------------------------------------------------------------- - bool Group::setStyle(const SGPropertyNode* style) + bool Group::setStyle( const SGPropertyNode* style, + const StyleInfo* style_info ) { - // Don't propagate styles directly applicable to this group - if( Element::setStyle(style) ) - return true; - - if( style->getParent() != _node - && _style.find(style->getNameString()) != _style.end() ) + if( !canApplyStyle(style) ) return false; - bool handled = false; - BOOST_FOREACH( ChildList::value_type child, _children ) + bool handled = setStyleImpl(style, style_info); + if( style_info->inheritable ) { - if( child.second->setStyle(style) ) - handled = true; + if( !_transform.valid() ) + { + warnTransformExpired("setStyle"); + return false; + } + + for(size_t i = 0; i < _transform->getNumChildren(); ++i) + handled |= getChildByIndex(i)->setStyle(style, style_info); } return handled; @@ -159,17 +221,23 @@ osg::BoundingBox Group::getTransformedBounds(const osg::Matrix& m) const { osg::BoundingBox bb; + if( !_transform.valid() ) + { + warnTransformExpired("getTransformedBounds"); + return bb; + } - BOOST_FOREACH( ChildList::value_type child, _children ) + for(size_t i = 0; i < _transform->getNumChildren(); ++i) { - if( !child.second->getMatrixTransform()->getNodeMask() ) + const ElementPtr& child = getChildByIndex(i); + if( !child->getMatrixTransform()->getNodeMask() ) continue; bb.expandBy ( - child.second->getTransformedBounds + child->getTransformedBounds ( - child.second->getMatrixTransform()->getMatrix() * m + child->getMatrixTransform()->getMatrix() * m ) ); } @@ -178,30 +246,41 @@ } //---------------------------------------------------------------------------- + ElementFactory Group::getChildFactory(const std::string& type) const + { + ElementFactories::iterator child_factory = _child_factories.find(type); + if( child_factory != _child_factories.end() ) + return child_factory->second; + + return ElementFactory(); + } + + //---------------------------------------------------------------------------- void Group::childAdded(SGPropertyNode* child) { if( child->getParent() != _node ) return; - ChildFactories::iterator child_factory = - _child_factories.find( child->getNameString() ); - if( child_factory != _child_factories.end() ) + ElementFactory child_factory = getChildFactory( child->getNameString() ); + if( child_factory ) { - ElementPtr element = child_factory->second(_canvas, child, _style, this); + if( !_transform.valid() ) + return warnTransformExpired("childAdded"); + + ElementPtr element = child_factory(_canvas, child, _style, this); // Add to osg scene graph... _transform->addChild( element->getMatrixTransform() ); - _children.push_back( ChildList::value_type(child, element) ); + + // ...and ensure correct ordering + handleZIndexChanged(element); return; } - if( !Element::setStyle(child) ) - { - // Only add style if not applicable to group itself + StyleInfo const* style = getStyleInfo(child->getNameString()); + if( style && style->inheritable ) _style[ child->getNameString() ] = child; - setStyle(child); - } } //---------------------------------------------------------------------------- @@ -210,10 +289,15 @@ if( node->getParent() != _node ) return; - if( _child_factories.find(node->getNameString()) != _child_factories.end() ) + if( getChildFactory(node->getNameString()) ) { - ChildList::iterator child = findChild(node); - if( child == _children.end() ) + if( !_transform.valid() ) + // If transform is destroyed also all children are destroyed, so we can + // not do anything here. + return; + + ElementPtr child = getChild(node); + if( !child ) SG_LOG ( SG_GL, @@ -222,15 +306,14 @@ ); else { - _transform->removeChild( child->second->getMatrixTransform() ); - _children.erase(child); + // Remove child from the scenegraph (this automatically invalidates the + // reference on the element hold by the MatrixTransform) + child->onDestroy(); } } else { - Style::iterator style = _style.find(node->getNameString()); - if( style != _style.end() ) - _style.erase(style); + _style.erase( node->getNameString() ); } } @@ -239,54 +322,52 @@ { if( node->getParent()->getParent() == _node && node->getNameString() == "z-index" ) - return handleZIndexChanged(node->getParent(), node->getIntValue()); + return handleZIndexChanged( getChild(node->getParent()), + node->getIntValue() ); } //---------------------------------------------------------------------------- - void Group::handleZIndexChanged(SGPropertyNode* node, int z_index) + void Group::handleZIndexChanged(ElementPtr child, int z_index) { - ChildList::iterator child = findChild(node); - if( child == _children.end() ) + if( !child || !_transform.valid() ) return; - osg::Node* tf = child->second->getMatrixTransform(); - int index = _transform->getChildIndex(tf), - index_new = index; + osg::ref_ptr tf = child->getMatrixTransform(); + size_t index = _transform->getChildIndex(tf), + index_new = index; - ChildList::iterator next = child; - ++next; - - while( next != _children.end() - && next->first->getIntValue("z-index", 0) <= z_index ) + for(;; ++index_new) { - ++index_new; - ++next; - } + if( index_new + 1 == _transform->getNumChildren() ) + break; - if( index_new != index ) - { - _children.insert(next, *child); + // Move to end of block with same index (= move upwards until the next + // element has a higher index) + if( getChildByIndex(index_new + 1)->get("z-index", 0) > z_index ) + break; } - else + + if( index_new == index ) { - ChildList::iterator prev = child; - while( prev != _children.begin() - && (--prev)->first->getIntValue("z-index", 0) > z_index) + // We were not able to move upwards so now try downwards + for(;; --index_new) { - --index_new; + if( index_new == 0 ) + break; + + // Move to end of block with same index (= move downwards until the + // previous element has the same or a lower index) + if( getChildByIndex(index_new - 1)->get("z-index", 0) <= z_index ) + break; } if( index == index_new ) return; - - _children.insert(prev, *child); } _transform->removeChild(index); _transform->insertChild(index_new, tf); - _children.erase(child); - SG_LOG ( SG_GENERAL, @@ -296,14 +377,42 @@ } //---------------------------------------------------------------------------- - Group::ChildList::iterator Group::findChild(const SGPropertyNode* node) + ElementPtr Group::getChildByIndex(size_t index) const { - return std::find_if - ( - _children.begin(), - _children.end(), - boost::bind(&ChildList::value_type::first, _1) == node - ); + assert(_transform.valid()); + OSGUserData* ud = + static_cast(_transform->getChild(index)->getUserData()); + assert(ud); + return ud->element; + } + + //---------------------------------------------------------------------------- + ElementPtr Group::findChild( const SGPropertyNode* node, + const std::string& id ) const + { + if( !_transform.valid() ) + { + warnTransformExpired("findChild"); + return ElementPtr(); + } + + for(size_t i = 0; i < _transform->getNumChildren(); ++i) + { + ElementPtr el = getChildByIndex(i); + + if( node ) + { + if( el->getProps() == node ) + return el; + } + else + { + if( el->get("id") == id ) + return el; + } + } + + return ElementPtr(); } } // namespace canvas diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasGroup.hxx simgear-3.0.0/simgear/canvas/elements/CanvasGroup.hxx --- simgear-2.10.0/simgear/canvas/elements/CanvasGroup.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasGroup.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -28,10 +28,15 @@ namespace canvas { + typedef std::map ElementFactories; + class Group: public Element { public: + static const std::string TYPE_NAME; + static void staticInit(); + typedef std::list< std::pair< const SGPropertyNode*, ElementPtr > @@ -46,6 +51,34 @@ ElementPtr createChild( const std::string& type, const std::string& id = "" ); ElementPtr getChild(const SGPropertyNode* node); + ElementPtr getChild(const std::string& id); + ElementPtr getOrCreateChild( const std::string& type, + const std::string& id ); + + template + boost::shared_ptr createChild(const std::string& id = "") + { + return boost::dynamic_pointer_cast( createChild(T::TYPE_NAME, id) ); + } + + template + boost::shared_ptr getChild(const SGPropertyNode* node) + { + return boost::dynamic_pointer_cast( getChild(node) ); + } + + template + boost::shared_ptr getChild(const std::string& id) + { + return boost::dynamic_pointer_cast( getChild(id) ); + } + + template + boost::shared_ptr getOrCreateChild(const std::string& id) + { + return + boost::dynamic_pointer_cast( getOrCreateChild(T::TYPE_NAME, id) ); + } /** * Get first child with given id (breadth-first search) @@ -54,28 +87,36 @@ */ ElementPtr getElementById(const std::string& id); + virtual void clearEventListener(); + virtual void update(double dt); virtual bool traverse(EventVisitor& visitor); - virtual bool setStyle(const SGPropertyNode* child); + virtual bool setStyle( const SGPropertyNode* child, + const StyleInfo* style_info = 0 ); virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const; protected: - typedef std::map ChildFactories; + static ElementFactories _child_factories; - ChildFactories _child_factories; - ChildList _children; + /** + * Overload in derived classes to allow for more/other types of elements + * to be managed. + */ + virtual ElementFactory getChildFactory(const std::string& type) const; virtual void childAdded(SGPropertyNode * child); virtual void childRemoved(SGPropertyNode * child); virtual void childChanged(SGPropertyNode * child); - void handleZIndexChanged(SGPropertyNode* node, int z_index); + void handleZIndexChanged(ElementPtr child, int z_index = 0); - ChildList::iterator findChild(const SGPropertyNode* node); + ElementPtr getChildByIndex(size_t index) const; + ElementPtr findChild( const SGPropertyNode* node, + const std::string& id ) const; }; } // namespace canvas diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasImage.cxx simgear-3.0.0/simgear/canvas/elements/CanvasImage.cxx --- simgear-2.10.0/simgear/canvas/elements/CanvasImage.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasImage.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -43,9 +45,11 @@ { public: CullCallback(const CanvasWeakPtr& canvas); + void cullNextFrame(); private: CanvasWeakPtr _canvas; + mutable bool _cull_next_frame; virtual bool cull( osg::NodeVisitor* nv, osg::Drawable* drawable, @@ -54,12 +58,19 @@ //---------------------------------------------------------------------------- CullCallback::CullCallback(const CanvasWeakPtr& canvas): - _canvas( canvas ) + _canvas( canvas ), + _cull_next_frame( false ) { } //---------------------------------------------------------------------------- + void CullCallback::cullNextFrame() + { + _cull_next_frame = true; + } + + //---------------------------------------------------------------------------- bool CullCallback::cull( osg::NodeVisitor* nv, osg::Drawable* drawable, osg::RenderInfo* renderInfo ) const @@ -67,8 +78,27 @@ if( !_canvas.expired() ) _canvas.lock()->enableRendering(); - // TODO check if window/image should be culled - return false; + if( !_cull_next_frame ) + // TODO check if window/image should be culled + return false; + + _cull_next_frame = false; + return true; + } + + //---------------------------------------------------------------------------- + const std::string Image::TYPE_NAME = "image"; + + //---------------------------------------------------------------------------- + void Image::staticInit() + { + if( isInit() ) + return; + + addStyle("fill", "color", &Image::setFill); + addStyle("slice", "", &Image::setSlice); + addStyle("slice-width", "", &Image::setSliceWidth); + addStyle("outset", "", &Image::setOutset); } //---------------------------------------------------------------------------- @@ -82,6 +112,8 @@ _src_rect(0,0), _region(0,0) { + staticInit(); + _geom = new osg::Geometry; _geom->setUseDisplayList(false); @@ -91,28 +123,26 @@ // allocate arrays for the image _vertices = new osg::Vec3Array(4); - _vertices->setDataVariance(osg::Object::STATIC); + _vertices->setDataVariance(osg::Object::DYNAMIC); _geom->setVertexArray(_vertices); _texCoords = new osg::Vec2Array(4); - _texCoords->setDataVariance(osg::Object::STATIC); + _texCoords->setDataVariance(osg::Object::DYNAMIC); _geom->setTexCoordArray(0, _texCoords); - _colors = new osg::Vec4Array(4); - _colors->setDataVariance(osg::Object::STATIC); - _geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX); + _colors = new osg::Vec4Array(1); + _colors->setDataVariance(osg::Object::DYNAMIC); _geom->setColorArray(_colors); + _geom->setColorBinding(osg::Geometry::BIND_OVERALL); - osg::DrawArrays* prim = new osg::DrawArrays(osg::PrimitiveSet::QUADS); - prim->set(osg::PrimitiveSet::QUADS, 0, 4); - prim->setDataVariance(osg::Object::STATIC); - _geom->addPrimitiveSet(prim); + _prim = new osg::DrawArrays(osg::PrimitiveSet::QUADS); + _prim->set(osg::PrimitiveSet::QUADS, 0, 4); + _prim->setDataVariance(osg::Object::DYNAMIC); + _geom->addPrimitiveSet(_prim); setDrawable(_geom); - addStyle("fill", &Image::setFill, this); setFill("#ffffff"); // TODO how should we handle default values? - setupStyle(); } @@ -127,14 +157,119 @@ { Element::update(dt); + osg::Texture2D* texture = dynamic_cast + ( + _geom->getOrCreateStateSet() + ->getTextureAttribute(0, osg::StateAttribute::TEXTURE) + ); + simgear::canvas::CanvasPtr canvas = _src_canvas.lock(); + + if( (_attributes_dirty & SRC_CANVAS) + // check if texture has changed (eg. due to resizing) + || (canvas && texture != canvas->getTexture()) ) + { + _geom->getOrCreateStateSet() + ->setTextureAttribute(0, canvas ? canvas->getTexture() : 0); + + if( !canvas || canvas->isInit() ) + _attributes_dirty &= ~SRC_CANVAS; + } + + if( !_attributes_dirty ) + return; + + const SGRect& tex_dim = getTextureDimensions(); + + // http://www.w3.org/TR/css3-background/#border-image-slice + + // The ‘fill’ keyword, if present, causes the middle part of the image to be + // preserved. (By default it is discarded, i.e., treated as empty.) + bool fill = (_slice.getKeyword() == "fill"); + if( _attributes_dirty & DEST_SIZE ) { - (*_vertices)[0].set(_region.l(), _region.t(), 0); - (*_vertices)[1].set(_region.r(), _region.t(), 0); - (*_vertices)[2].set(_region.r(), _region.b(), 0); - (*_vertices)[3].set(_region.l(), _region.b(), 0); - _vertices->dirty(); + size_t num_vertices = (_slice.isValid() ? (fill ? 9 : 8) : 1) * 4; + + if( num_vertices != _prim->getNumPrimitives() ) + { + _vertices->resize(num_vertices); + _texCoords->resize(num_vertices); + _prim->setCount(num_vertices); + _prim->dirty(); + + _attributes_dirty |= SRC_RECT; + } + + // http://www.w3.org/TR/css3-background/#border-image-outset + SGRect region = _region; + if( _outset.isValid() ) + { + const CSSBorder::Offsets& outset = _outset.getAbsOffsets(tex_dim); + region.t() -= outset.t; + region.r() += outset.r; + region.b() += outset.b; + region.l() -= outset.l; + } + + if( !_slice.isValid() ) + { + setQuad(0, region.getMin(), region.getMax()); + } + else + { + /* + Image slice, 9-scale, whatever it is called. The four corner images + stay unscaled (tl, tr, bl, br) whereas the other parts are scaled to + fill the remaining space up to the specified size. + + x[0] x[1] x[2] x[3] + | | | | + -------------------- - y[0] + | tl | top | tr | + -------------------- - y[1] + | | | | + | l | | r | + | e | center | i | + | f | | g | + | t | | h | + | | | t | + -------------------- - y[2] + | bl | bottom | br | + -------------------- - y[3] + */ + + const CSSBorder::Offsets& slice = + (_slice_width.isValid() ? _slice_width : _slice) + .getAbsOffsets(tex_dim); + float x[4] = { + region.l(), + region.l() + slice.l, + region.r() - slice.r, + region.r() + }; + float y[4] = { + region.t(), + region.t() + slice.t, + region.b() - slice.b, + region.b() + }; + + int i = 0; + for(int ix = 0; ix < 3; ++ix) + for(int iy = 0; iy < 3; ++iy) + { + if( ix == 1 && iy == 1 && !fill ) + // The ‘fill’ keyword, if present, causes the middle part of the + // image to be filled. + continue; + + setQuad( i++, + SGVec2f(x[ix ], y[iy ]), + SGVec2f(x[ix + 1], y[iy + 1]) ); + } + } + _vertices->dirty(); _attributes_dirty &= ~DEST_SIZE; _geom->dirtyBound(); setBoundingBox(_geom->getBound()); @@ -142,46 +277,105 @@ if( _attributes_dirty & SRC_RECT ) { - double u0 = _src_rect.l(), - u1 = _src_rect.r(), - v0 = _src_rect.b(), - v1 = _src_rect.t(); - + SGRect src_rect = _src_rect; if( !_node_src_rect->getBoolValue("normalized", true) ) { - const SGRect& tex_dim = getTextureDimensions(); + src_rect.t() /= tex_dim.height(); + src_rect.r() /= tex_dim.width(); + src_rect.b() /= tex_dim.height(); + src_rect.l() /= tex_dim.width(); + } + + // Image coordinate systems y-axis is flipped + std::swap(src_rect.t(), src_rect.b()); - u0 /= tex_dim.width(); - u1 /= tex_dim.width(); - v0 /= tex_dim.height(); - v1 /= tex_dim.height(); + if( !_slice.isValid() ) + { + setQuadUV(0, src_rect.getMin(), src_rect.getMax()); + } + else + { + const CSSBorder::Offsets& slice = _slice.getRelOffsets(tex_dim); + float x[4] = { + src_rect.l(), + src_rect.l() + slice.l, + src_rect.r() - slice.r, + src_rect.r() + }; + float y[4] = { + src_rect.t(), + src_rect.t() - slice.t, + src_rect.b() + slice.b, + src_rect.b() + }; + + int i = 0; + for(int ix = 0; ix < 3; ++ix) + for(int iy = 0; iy < 3; ++iy) + { + if( ix == 1 && iy == 1 && !fill ) + // The ‘fill’ keyword, if present, causes the middle part of the + // image to be filled. + continue; + + setQuadUV( i++, + SGVec2f(x[ix ], y[iy ]), + SGVec2f(x[ix + 1], y[iy + 1]) ); + } } - (*_texCoords)[0].set(u0, v0); - (*_texCoords)[1].set(u1, v0); - (*_texCoords)[2].set(u1, v1); - (*_texCoords)[3].set(u0, v1); _texCoords->dirty(); - _attributes_dirty &= ~SRC_RECT; } } //---------------------------------------------------------------------------- + void Image::valueChanged(SGPropertyNode* child) + { + // If the image is switched from invisible to visible, and it shows a + // canvas, we need to delay showing it by one frame to ensure the canvas is + // updated before the image is displayed. + // + // As canvas::Element handles and filters changes to the "visible" property + // we can not check this in Image::childChanged but instead have to override + // Element::valueChanged. + if( !isVisible() + && child->getParent() == _node + && child->getNameString() == "visible" + && child->getBoolValue() ) + { + CullCallback* cb = static_cast(_geom->getCullCallback()); + if( cb ) + cb->cullNextFrame(); + } + + Element::valueChanged(child); + } + + //---------------------------------------------------------------------------- void Image::setSrcCanvas(CanvasPtr canvas) { - if( !_src_canvas.expired() ) - _src_canvas.lock()->removeDependentCanvas(_canvas); + CanvasPtr src_canvas = _src_canvas.lock(), + self_canvas = _canvas.lock(); - _src_canvas = canvas; - _geom->getOrCreateStateSet() - ->setTextureAttribute(0, canvas ? canvas->getTexture() : 0); + if( src_canvas ) + src_canvas->removeParentCanvas(self_canvas); + if( self_canvas ) + self_canvas->removeChildCanvas(src_canvas); + + _src_canvas = src_canvas = canvas; + _attributes_dirty |= SRC_CANVAS; _geom->setCullCallback(canvas ? new CullCallback(canvas) : 0); - if( !_src_canvas.expired() ) + if( src_canvas ) { setupDefaultDimensions(); - _src_canvas.lock()->addDependentCanvas(_canvas); + + if( self_canvas ) + { + self_canvas->addChildCanvas(src_canvas); + src_canvas->addParentCanvas(self_canvas); + } } } @@ -197,7 +391,10 @@ // remove canvas... setSrcCanvas( CanvasPtr() ); + _texture->setResizeNonPowerOfTwoHint(false); _texture->setImage(img); + _texture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); + _texture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); _geom->getOrCreateStateSet() ->setTextureAttributeAndModes(0, _texture); @@ -208,22 +405,81 @@ //---------------------------------------------------------------------------- void Image::setFill(const std::string& fill) { - osg::Vec4 color; - if( !parseColor(fill, color) ) + osg::Vec4 color(1,1,1,1); + if( !fill.empty() // If no color is given default to white + && !parseColor(fill, color) ) return; - for( int i = 0; i < 4; ++i ) - (*_colors)[i] = color; + _colors->front() = color; _colors->dirty(); } //---------------------------------------------------------------------------- + void Image::setSlice(const std::string& slice) + { + _slice = CSSBorder::parse(slice); + _attributes_dirty |= SRC_RECT | DEST_SIZE; + } + + //---------------------------------------------------------------------------- + void Image::setSliceWidth(const std::string& width) + { + _slice_width = CSSBorder::parse(width); + _attributes_dirty |= DEST_SIZE; + } + + //---------------------------------------------------------------------------- + void Image::setOutset(const std::string& outset) + { + _outset = CSSBorder::parse(outset); + _attributes_dirty |= DEST_SIZE; + } + + //---------------------------------------------------------------------------- const SGRect& Image::getRegion() const { return _region; } //---------------------------------------------------------------------------- + bool Image::handleEvent(EventPtr event) + { + bool handled = Element::handleEvent(event); + + CanvasPtr src_canvas = _src_canvas.lock(); + if( !src_canvas ) + return handled; + + MouseEventPtr mouse_event = boost::dynamic_pointer_cast(event); + if( mouse_event ) + { + mouse_event.reset( new MouseEvent(*mouse_event) ); + event = mouse_event; + + mouse_event->client_pos = mouse_event->local_pos + - toOsg(_region.getMin()); + + osg::Vec2f size(_region.width(), _region.height()); + if( _outset.isValid() ) + { + CSSBorder::Offsets outset = + _outset.getAbsOffsets(getTextureDimensions()); + + mouse_event->client_pos += osg::Vec2f(outset.l, outset.t); + size.x() += outset.l + outset.r; + size.y() += outset.t + outset.b; + } + + // Scale event pos according to canvas view size vs. displayed/screen size + mouse_event->client_pos.x() *= src_canvas->getViewWidth() / size.x(); + mouse_event->client_pos.y() *= src_canvas->getViewHeight()/ size.y(); + mouse_event->local_pos = mouse_event->client_pos; + } + + return handled | src_canvas->handleMouseEvent(mouse_event); + } + + //---------------------------------------------------------------------------- void Image::childChanged(SGPropertyNode* child) { const std::string& name = child->getNameString(); @@ -309,7 +565,7 @@ } else { - setImage( canvas->getSystemAdapter()->getImage(path) ); + setImage( Canvas::getSystemAdapter()->getImage(path) ); } } } @@ -319,36 +575,67 @@ { if( !_src_rect.width() || !_src_rect.height() ) { - const SGRect& tex_dim = getTextureDimensions(); - - _node_src_rect->setBoolValue("normalized", false); - _node_src_rect->setFloatValue("right", tex_dim.width()); - _node_src_rect->setFloatValue("bottom", tex_dim.height()); + // Show whole image by default + _node_src_rect->setBoolValue("normalized", true); + _node_src_rect->setFloatValue("right", 1); + _node_src_rect->setFloatValue("bottom", 1); } if( !_region.width() || !_region.height() ) { - _node->setFloatValue("size[0]", _src_rect.width()); - _node->setFloatValue("size[1]", _src_rect.height()); + // Default to image size. + // TODO handle showing only part of image? + const SGRect& dim = getTextureDimensions(); + _node->setFloatValue("size[0]", dim.width()); + _node->setFloatValue("size[1]", dim.height()); } } //---------------------------------------------------------------------------- SGRect Image::getTextureDimensions() const { - osg::Texture2D *texture = !_src_canvas.expired() - ? _src_canvas.lock()->getTexture() - : _texture.get(); + CanvasPtr canvas = _src_canvas.lock(); + SGRect dim(0,0); - if( !texture ) - return SGRect(); + // Use canvas/image dimensions rather than texture dimensions, as they could + // be resized internally by OpenSceneGraph (eg. to nearest power of two). + if( canvas ) + { + dim.setRight( canvas->getViewWidth() ); + dim.setBottom( canvas->getViewHeight() ); + } + else if( _texture ) + { + osg::Image* img = _texture->getImage(); - return SGRect - ( - 0,0, - texture->getTextureWidth(), - texture->getTextureHeight() - ); + if( img ) + { + dim.setRight( img->s() ); + dim.setBottom( img->t() ); + } + } + + return dim; + } + + //---------------------------------------------------------------------------- + void Image::setQuad(size_t index, const SGVec2f& tl, const SGVec2f& br) + { + int i = index * 4; + (*_vertices)[i + 0].set(tl.x(), tl.y(), 0); + (*_vertices)[i + 1].set(br.x(), tl.y(), 0); + (*_vertices)[i + 2].set(br.x(), br.y(), 0); + (*_vertices)[i + 3].set(tl.x(), br.y(), 0); + } + + //---------------------------------------------------------------------------- + void Image::setQuadUV(size_t index, const SGVec2f& tl, const SGVec2f& br) + { + int i = index * 4; + (*_texCoords)[i + 0].set(tl.x(), tl.y()); + (*_texCoords)[i + 1].set(br.x(), tl.y()); + (*_texCoords)[i + 2].set(br.x(), br.y()); + (*_texCoords)[i + 3].set(tl.x(), br.y()); } } // namespace canvas diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasImage.hxx simgear-3.0.0/simgear/canvas/elements/CanvasImage.hxx --- simgear-2.10.0/simgear/canvas/elements/CanvasImage.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasImage.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -22,7 +22,7 @@ #include "CanvasElement.hxx" #include -#include +#include #include namespace simgear @@ -34,6 +34,9 @@ public Element { public: + static const std::string TYPE_NAME; + static void staticInit(); + /** * @param node Property node containing settings for this image: * rect/[left/right/top/bottom] Dimensions of source @@ -43,11 +46,12 @@ */ Image( const CanvasWeakPtr& canvas, const SGPropertyNode_ptr& node, - const Style& parent_style, + const Style& parent_style = Style(), Element* parent = 0 ); virtual ~Image(); virtual void update(double dt); + virtual void valueChanged(SGPropertyNode* child); void setSrcCanvas(CanvasPtr canvas); CanvasWeakPtr getSrcCanvas() const; @@ -55,14 +59,40 @@ void setImage(osg::Image *img); void setFill(const std::string& fill); + /** + * Set image slice (aka. 9-scale) + * + * @see http://www.w3.org/TR/css3-background/#border-image-slice + */ + void setSlice(const std::string& slice); + + /** + * Set image slice width. + * + * By default the size of the 9-scale grid is the same as specified + * with setSlice/"slice". Using this method allows setting values + * different to the size in the source image. + * + * @see http://www.w3.org/TR/css3-background/#border-image-width + */ + void setSliceWidth(const std::string& width); + + /** + * http://www.w3.org/TR/css3-background/#border-image-outset + */ + void setOutset(const std::string& outset); + const SGRect& getRegion() const; + bool handleEvent(EventPtr event); + protected: enum ImageAttributes { SRC_RECT = LAST_ATTRIBUTE << 1, // Source image rectangle - DEST_SIZE = SRC_RECT << 1 // Element size + DEST_SIZE = SRC_RECT << 1, // Element size + SRC_CANVAS = DEST_SIZE << 1 }; virtual void childChanged(SGPropertyNode * child); @@ -70,11 +100,15 @@ void setupDefaultDimensions(); SGRect getTextureDimensions() const; + void setQuad(size_t index, const SGVec2f& tl, const SGVec2f& br); + void setQuadUV(size_t index, const SGVec2f& tl, const SGVec2f& br); + osg::ref_ptr _texture; // TODO optionally forward events to canvas CanvasWeakPtr _src_canvas; osg::ref_ptr _geom; + osg::ref_ptr_prim; osg::ref_ptr _vertices; osg::ref_ptr _texCoords; osg::ref_ptr _colors; @@ -82,6 +116,10 @@ SGPropertyNode *_node_src_rect; SGRect _src_rect, _region; + + CSSBorder _slice, + _slice_width, + _outset; }; } // namespace canvas diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasMap.cxx simgear-3.0.0/simgear/canvas/elements/CanvasMap.cxx --- simgear-2.10.0/simgear/canvas/elements/CanvasMap.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasMap.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -42,7 +42,20 @@ namespace canvas { + //---------------------------------------------------------------------------- const std::string GEO = "-geo"; + const std::string Map::TYPE_NAME = "map"; + + //---------------------------------------------------------------------------- + void Map::staticInit() + { + Group::staticInit(); + + if( isInit() ) + return; + + // Do some initialization if needed... + } //---------------------------------------------------------------------------- Map::Map( const CanvasWeakPtr& canvas, @@ -54,7 +67,7 @@ _projection(new SansonFlamsteedProjection), _projection_dirty(true) { - + staticInit(); } //---------------------------------------------------------------------------- @@ -192,6 +205,8 @@ _projection->setOrientation(child->getFloatValue()); else if( child->getNameString() == "range" ) _projection->setRange(child->getDoubleValue()); + else if( child->getNameString() == "screen-range" ) + _projection->setScreenRange(child->getDoubleValue()); else return Group::childChanged(child); diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasMap.hxx simgear-3.0.0/simgear/canvas/elements/CanvasMap.hxx --- simgear-2.10.0/simgear/canvas/elements/CanvasMap.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasMap.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -35,6 +35,9 @@ public Group { public: + static const std::string TYPE_NAME; + static void staticInit(); + Map( const CanvasWeakPtr& canvas, const SGPropertyNode_ptr& node, const Style& parent_style, diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasPath.cxx simgear-3.0.0/simgear/canvas/elements/CanvasPath.cxx --- simgear-2.10.0/simgear/canvas/elements/CanvasPath.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasPath.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -20,7 +20,6 @@ #include #include -#include #include #include @@ -111,7 +110,7 @@ */ void setFill(const std::string& fill) { - if( fill == "none" ) + if( fill.empty() || fill == "none" ) { _mode &= ~VG_FILL_PATH; } @@ -151,7 +150,7 @@ */ void setStroke(const std::string& stroke) { - if( stroke == "none" ) + if( stroke.empty() || stroke == "none" ) { _mode &= ~VG_STROKE_PATH; } @@ -278,7 +277,8 @@ { osg::BoundingBox bb; - osg::Vec2f cur; // VG "Current point" (in local coordinates) + osg::Vec2f cur(0, 0), // VG "Current point" (in local coordinates) + sub(0, 0); // beginning of current sub path VGubyte cmd_index = 0; for( size_t i = 0, ci = 0; i < _cmds.size() && ci < _coords.size(); @@ -298,6 +298,7 @@ switch( cmd ) { case VG_CLOSE_PATH: + cur = sub; break; case VG_MOVE_TO: case VG_LINE_TO: @@ -353,7 +354,12 @@ } if( num_coords > 0 ) + { cur = points[ num_coords - 1 ]; + + if( cmd == VG_MOVE_TO ) + sub = cur; + } } return bb; @@ -429,6 +435,9 @@ */ void update() { + if( !vgHasContextSH() ) + return; + if( _attributes_dirty & PATH ) { const VGbitfield caps = VG_PATH_CAPABILITY_APPEND_TO @@ -468,6 +477,25 @@ }; //---------------------------------------------------------------------------- + const std::string Path::TYPE_NAME = "path"; + + //---------------------------------------------------------------------------- + void Path::staticInit() + { + if( isInit() ) + return; + + PathDrawableRef Path::*path = &Path::_path; + + addStyle("fill", "color", &PathDrawable::setFill, path); + addStyle("fill-rule", "", &PathDrawable::setFillRule, path); + addStyle("stroke", "color", &PathDrawable::setStroke, path); + addStyle("stroke-width", "numeric", &PathDrawable::setStrokeWidth, path); + addStyle("stroke-dasharray", "", &PathDrawable::setStrokeDashArray, path); + addStyle("stroke-linecap", "", &PathDrawable::setStrokeLinecap, path); + } + + //---------------------------------------------------------------------------- Path::Path( const CanvasWeakPtr& canvas, const SGPropertyNode_ptr& node, const Style& parent_style, @@ -475,16 +503,9 @@ Element(canvas, node, parent_style, parent), _path( new PathDrawable(this) ) { - setDrawable(_path); - PathDrawable *path = _path.get(); - - addStyle("fill", &PathDrawable::setFill, path); - addStyle("fill-rule", &PathDrawable::setFillRule, path); - addStyle("stroke", &PathDrawable::setStroke, path); - addStyle("stroke-width", &PathDrawable::setStrokeWidth, path); - addStyle("stroke-dasharray", &PathDrawable::setStrokeDashArray, path); - addStyle("stroke-linecap", &PathDrawable::setStrokeLinecap, path); + staticInit(); + setDrawable(_path); setupStyle(); } @@ -518,6 +539,60 @@ } //---------------------------------------------------------------------------- + Path& Path::moveTo(float x_abs, float y_abs) + { + return addSegment(VG_MOVE_TO_ABS, x_abs, y_abs); + } + + //---------------------------------------------------------------------------- + Path& Path::move(float x_rel, float y_rel) + { + return addSegment(VG_MOVE_TO_REL, x_rel, y_rel); + } + + //---------------------------------------------------------------------------- + Path& Path::lineTo(float x_abs, float y_abs) + { + return addSegment(VG_LINE_TO_ABS, x_abs, y_abs); + } + + //---------------------------------------------------------------------------- + Path& Path::line(float x_rel, float y_rel) + { + return addSegment(VG_LINE_TO_REL, x_rel, y_rel); + } + + //---------------------------------------------------------------------------- + Path& Path::horizTo(float x_abs) + { + return addSegment(VG_HLINE_TO_ABS, x_abs); + } + + //---------------------------------------------------------------------------- + Path& Path::horiz(float x_rel) + { + return addSegment(VG_HLINE_TO_REL, x_rel); + } + + //---------------------------------------------------------------------------- + Path& Path::vertTo(float y_abs) + { + return addSegment(VG_VLINE_TO_ABS, y_abs); + } + + //---------------------------------------------------------------------------- + Path& Path::vert(float y_rel) + { + return addSegment(VG_VLINE_TO_REL, y_rel); + } + + //---------------------------------------------------------------------------- + Path& Path::close() + { + return addSegment(VG_CLOSE_PATH); + } + + //---------------------------------------------------------------------------- void Path::childRemoved(SGPropertyNode* child) { childChanged(child); diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasPath.hxx simgear-3.0.0/simgear/canvas/elements/CanvasPath.hxx --- simgear-2.10.0/simgear/canvas/elements/CanvasPath.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasPath.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -20,6 +20,7 @@ #define CANVAS_PATH_HXX_ #include "CanvasElement.hxx" +#include namespace simgear { @@ -29,6 +30,9 @@ public Element { public: + static const std::string TYPE_NAME; + static void staticInit(); + Path( const CanvasWeakPtr& canvas, const SGPropertyNode_ptr& node, const Style& parent_style, @@ -39,6 +43,30 @@ virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const; +#define BOOST_PP_ITERATION_LIMITS (0, 6) +#define BOOST_PP_FILENAME_1 \ + +#include BOOST_PP_ITERATE() + + /** Move path cursor */ + Path& moveTo(float x_abs, float y_abs); + Path& move(float x_rel, float y_rel); + + /** Add a line */ + Path& lineTo(float x_abs, float y_abs); + Path& line(float x_rel, float y_rel); + + /** Add a horizontal line */ + Path& horizTo(float x_abs); + Path& horiz(float x_rel); + + /** Add a vertical line */ + Path& vertTo(float y_abs); + Path& vert(float y_rel); + + /** Close the path (implicit lineTo to first point of path) */ + Path& close(); + protected: enum PathAttributes @@ -48,7 +76,8 @@ }; class PathDrawable; - osg::ref_ptr _path; + typedef osg::ref_ptr PathDrawableRef; + PathDrawableRef _path; virtual void childRemoved(SGPropertyNode * child); virtual void childChanged(SGPropertyNode * child); diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasText.cxx simgear-3.0.0/simgear/canvas/elements/CanvasText.cxx --- simgear-2.10.0/simgear/canvas/elements/CanvasText.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasText.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -20,6 +20,7 @@ #include #include #include +#include #include namespace simgear @@ -33,7 +34,9 @@ TextOSG(canvas::Text* text); + void setFontResolution(int res); void setCharacterAspect(float aspect); + void setLineHeight(float factor); void setFill(const std::string& fill); void setBackgroundColor(const std::string& fill); @@ -44,13 +47,21 @@ protected: canvas::Text *_text_element; + + virtual void computePositions(unsigned int contextID) const; }; //---------------------------------------------------------------------------- Text::TextOSG::TextOSG(canvas::Text* text): _text_element(text) { + setBackdropImplementation(NO_DEPTH_BUFFER); + } + //---------------------------------------------------------------------------- + void Text::TextOSG::setFontResolution(int res) + { + TextBase::setFontResolution(res, res); } //---------------------------------------------------------------------------- @@ -60,6 +71,12 @@ } //---------------------------------------------------------------------------- + void Text::TextOSG::setLineHeight(float factor) + { + setLineSpacing(factor - 1); + } + + //---------------------------------------------------------------------------- void Text::TextOSG::setFill(const std::string& fill) { // if( fill == "none" ) @@ -165,10 +182,12 @@ if( !bb.valid() ) return bb; +#if OSG_VERSION_LESS_THAN(3,1,0) // TODO bounding box still doesn't seem always right (eg. with center // horizontal alignment not completely accurate) bb._min.y() += _offset.y(); bb._max.y() += _offset.y(); +#endif _text_element->setBoundingBox(bb); @@ -176,6 +195,106 @@ } //---------------------------------------------------------------------------- + void Text::TextOSG::computePositions(unsigned int contextID) const + { + if( _textureGlyphQuadMap.empty() || _layout == VERTICAL ) + return osgText::Text::computePositions(contextID); + + // TODO check when it can be larger + assert( _textureGlyphQuadMap.size() == 1 ); + + const GlyphQuads& quads = _textureGlyphQuadMap.begin()->second; + const GlyphQuads::Glyphs& glyphs = quads._glyphs; + const GlyphQuads::Coords2& coords = quads._coords; + const GlyphQuads::LineNumbers& line_numbers = quads._lineNumbers; + + float wr = _characterHeight / getCharacterAspectRatio(); + + size_t cur_line = static_cast(-1); + for(size_t i = 0; i < glyphs.size(); ++i) + { + // Check horizontal offsets + + bool first_char = cur_line != line_numbers[i]; + cur_line = line_numbers[i]; + + bool last_char = (i + 1 == glyphs.size()) + || (cur_line != line_numbers[i + 1]); + + if( first_char || last_char ) + { + // From osg/src/osgText/Text.cpp: + // + // osg::Vec2 upLeft = local+osg::Vec2(0.0f-fHorizQuadMargin, ...); + // osg::Vec2 lowLeft = local+osg::Vec2(0.0f-fHorizQuadMargin, ...); + // osg::Vec2 lowRight = local+osg::Vec2(width+fHorizQuadMargin, ...); + // osg::Vec2 upRight = local+osg::Vec2(width+fHorizQuadMargin, ...); + + float left = coords[i * 4].x(), + right = coords[i * 4 + 2].x(), + width = glyphs[i]->getWidth() * wr; + + // (local + width + fHoriz) - (local - fHoriz) = width + 2*fHoriz | -width + float margin = 0.5f * (right - left - width), + cursor_x = left + margin + - glyphs[i]->getHorizontalBearing().x() * wr; + + if( first_char ) + { + if( cur_line == 0 || cursor_x < _textBB._min.x() ) + _textBB._min.x() = cursor_x; + } + + if( last_char ) + { + float cursor_w = cursor_x + glyphs[i]->getHorizontalAdvance() * wr; + + if( cur_line == 0 || cursor_w > _textBB._max.x() ) + _textBB._max.x() = cursor_w; + } + } + } + + return osgText::Text::computePositions(contextID); + } + + //---------------------------------------------------------------------------- + const std::string Text::TYPE_NAME = "text"; + + //---------------------------------------------------------------------------- + void Text::staticInit() + { + if( isInit() ) + return; + + osg::ref_ptr Text::*text = &Text::_text; + + addStyle("fill", "color", &TextOSG::setFill, text); + addStyle("background", "color", &TextOSG::setBackgroundColor, text); + addStyle("character-size", + "numeric", + static_cast< + void (TextOSG::*)(float) + > (&TextOSG::setCharacterSize), + text); + addStyle("character-aspect-ratio", + "numeric", + &TextOSG::setCharacterAspect, text); + addStyle("line-height", "numeric", &TextOSG::setLineHeight, text); + addStyle("font-resolution", "numeric", &TextOSG::setFontResolution, text); + addStyle("padding", "numeric", &TextOSG::setBoundingBoxMargin, text); + // TEXT = 1 default + // BOUNDINGBOX = 2 + // FILLEDBOUNDINGBOX = 4 + // ALIGNMENT = 8 + addStyle("draw-mode", "", &TextOSG::setDrawMode, text); + addStyle("max-width", "numeric", &TextOSG::setMaximumWidth, text); + addStyle("font", "", &Text::setFont); + addStyle("alignment", "", &Text::setAlignment); + addStyle("text", "", &Text::setText, false); + } + + //---------------------------------------------------------------------------- Text::Text( const CanvasWeakPtr& canvas, const SGPropertyNode_ptr& node, const Style& parent_style, @@ -183,28 +302,13 @@ Element(canvas, node, parent_style, parent), _text( new Text::TextOSG(this) ) { + staticInit(); + setDrawable(_text); _text->setCharacterSizeMode(osgText::Text::OBJECT_COORDS); _text->setAxisAlignment(osgText::Text::USER_DEFINED_ROTATION); _text->setRotation(osg::Quat(osg::PI, osg::X_AXIS)); - addStyle("fill", &TextOSG::setFill, _text); - addStyle("background", &TextOSG::setBackgroundColor, _text); - addStyle("character-size", - static_cast(&TextOSG::setCharacterSize), - _text); - addStyle("character-aspect-ratio", &TextOSG::setCharacterAspect, _text); - addStyle("padding", &TextOSG::setBoundingBoxMargin, _text); - // TEXT = 1 default - // BOUNDINGBOX = 2 - // FILLEDBOUNDINGBOX = 4 - // ALIGNMENT = 8 - addStyle("draw-mode", &TextOSG::setDrawMode, _text); - addStyle("max-width", &TextOSG::setMaximumWidth, _text); - addStyle("font", &Text::setFont, this); - addStyle("alignment", &Text::setAlignment, this); - addStyle("text", &Text::setText, this); - setupStyle(); } @@ -223,7 +327,7 @@ //---------------------------------------------------------------------------- void Text::setFont(const char* name) { - _text->setFont( _canvas.lock()->getSystemAdapter()->getFont(name) ); + _text->setFont( Canvas::getSystemAdapter()->getFont(name) ); } //---------------------------------------------------------------------------- diff -Nru simgear-2.10.0/simgear/canvas/elements/CanvasText.hxx simgear-3.0.0/simgear/canvas/elements/CanvasText.hxx --- simgear-2.10.0/simgear/canvas/elements/CanvasText.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CanvasText.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -33,6 +33,9 @@ public Element { public: + static const std::string TYPE_NAME; + static void staticInit(); + Text( const CanvasWeakPtr& canvas, const SGPropertyNode_ptr& node, const Style& parent_style, diff -Nru simgear-2.10.0/simgear/canvas/elements/CMakeLists.txt simgear-3.0.0/simgear/canvas/elements/CMakeLists.txt --- simgear-2.10.0/simgear/canvas/elements/CMakeLists.txt 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -6,7 +6,11 @@ CanvasImage.hxx CanvasMap.hxx CanvasPath.hxx - CanvasText.hxx + CanvasText.hxx +) + +set(DETAIL_HEADERS + detail/add_segment_variadic.hxx ) set(SOURCES @@ -18,4 +22,5 @@ CanvasText.cxx ) -simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}") \ No newline at end of file +simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}") +simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}") \ No newline at end of file diff -Nru simgear-2.10.0/simgear/canvas/elements/detail/add_segment_variadic.hxx simgear-3.0.0/simgear/canvas/elements/detail/add_segment_variadic.hxx --- simgear-2.10.0/simgear/canvas/elements/detail/add_segment_variadic.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/elements/detail/add_segment_variadic.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,21 @@ +#ifndef CANVAS_PATH_HXX_ +# error Canvas - do not include this file! +#endif + +#define n BOOST_PP_ITERATION() + +Path& addSegment( uint8_t cmd + BOOST_PP_COMMA_IF(n) + BOOST_PP_ENUM_PARAMS(n, float coord) ) +{ + _node->addChild("cmd")->setIntValue(cmd); + +#define SG_CANVAS_PATH_SET_COORD(z, n, dummy)\ + _node->addChild("coord")->setFloatValue(coord##n); + + BOOST_PP_REPEAT(n, SG_CANVAS_PATH_SET_COORD, 0) +#undef SG_CANVAS_PATH_SET_COORD + return *this; +} + +#undef n diff -Nru simgear-2.10.0/simgear/canvas/MouseEvent.hxx simgear-3.0.0/simgear/canvas/MouseEvent.hxx --- simgear-2.10.0/simgear/canvas/MouseEvent.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/MouseEvent.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -38,8 +38,18 @@ click_count(0) {} + MouseEvent(const osgGA::GUIEventAdapter& ea): + button(ea.getButton()), + state(ea.getButtonMask()), + mod(ea.getModKeyMask()), + click_count(0) + { + time = ea.getTime(); + } + osg::Vec2f getScreenPos() const { return screen_pos; } osg::Vec2f getClientPos() const { return client_pos; } + osg::Vec2f getLocalPos() const { return local_pos; } osg::Vec2f getDelta() const { return delta; } float getScreenX() const { return screen_pos.x(); } @@ -48,6 +58,9 @@ float getClientX() const { return client_pos.x(); } float getClientY() const { return client_pos.y(); } + float getLocalX() const { return local_pos.x(); } + float getLocalY() const { return local_pos.y(); } + float getDeltaX() const { return delta.x(); } float getDeltaY() const { return delta.y(); } @@ -55,6 +68,7 @@ osg::Vec2f screen_pos, // @@ -43,6 +44,7 @@ #include #include #include // for GL_DEPTH_STENCIL_EXT on Windows +#include #include @@ -51,18 +53,67 @@ namespace canvas { + class PreOrderBin: + public osgUtil::RenderBin + { + public: + + PreOrderBin() + {} + PreOrderBin( const RenderBin& rhs, + const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY ): + RenderBin(rhs, copyop) + {} + + virtual osg::Object* cloneType() const + { + return new PreOrderBin(); + } + virtual osg::Object* clone(const osg::CopyOp& copyop) const + { + return new PreOrderBin(*this,copyop); + } + virtual bool isSameKindAs(const osg::Object* obj) const + { + return dynamic_cast(obj) != 0L; + } + virtual const char* className() const + { + return "PreOrderBin"; + } + + virtual void sort() + { + // Do not sort to keep traversal order... + } + }; + +#ifndef OSG_INIT_SINGLETON_PROXY + /** + * http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk/include/osg/Object + * + * Helper macro that creates a static proxy object to call singleton function + * on it's construction, ensuring that the singleton gets initialized at + * startup. + */ +# define OSG_INIT_SINGLETON_PROXY(ProxyName, Func)\ + static struct ProxyName{ ProxyName() { Func; } } s_##ProxyName; +#endif + + OSG_INIT_SINGLETON_PROXY( + PreOrderBinProxy, + (osgUtil::RenderBin::addRenderBinPrototype("PreOrderBin", new PreOrderBin)) + ); + //---------------------------------------------------------------------------- ODGauge::ODGauge(): _size_x( -1 ), _size_y( -1 ), _view_width( -1 ), _view_height( -1 ), - _use_image_coords( false ), - _use_stencil( false ), - _use_mipmapping( false ), + _flags(0), _coverage_samples( 0 ), - _color_samples( 0 ), - rtAvailable( false ) + _color_samples( 0 ) { } @@ -74,12 +125,6 @@ } //---------------------------------------------------------------------------- - void ODGauge::setSystemAdapter(const SystemAdapterPtr& system_adapter) - { - _system_adapter = system_adapter; - } - - //---------------------------------------------------------------------------- void ODGauge::setSize(int size_x, int size_y) { _size_x = size_x; @@ -102,41 +147,42 @@ } //---------------------------------------------------------------------------- - void ODGauge::useImageCoords(bool use) + osg::Vec2s ODGauge::getViewSize() const { - if( use == _use_image_coords ) - return; - - _use_image_coords = use; + return osg::Vec2s(_view_width, _view_height); + } - if( texture ) + //---------------------------------------------------------------------------- + void ODGauge::useImageCoords(bool use) + { + if( updateFlag(USE_IMAGE_COORDS, use) && texture ) updateCoordinateFrame(); } //---------------------------------------------------------------------------- void ODGauge::useStencil(bool use) { - if( use == _use_stencil ) - return; - - _use_stencil = use; - - if( texture ) + if( updateFlag(USE_STENCIL, use) && texture ) updateStencil(); } //---------------------------------------------------------------------------- + void ODGauge::useAdditiveBlend(bool use) + { + if( updateFlag(USE_ADDITIVE_BLEND, use) && camera ) + updateBlendMode(); + } + + //---------------------------------------------------------------------------- void ODGauge::setSampling( bool mipmapping, - int coverage_samples, - int color_samples ) + int coverage_samples, + int color_samples ) { - if( _use_mipmapping == mipmapping + if( !updateFlag(USE_MIPMAPPING, mipmapping) && _coverage_samples == coverage_samples && _color_samples == color_samples ) return; - _use_mipmapping = mipmapping; - if( color_samples > coverage_samples ) { SG_LOG @@ -162,9 +208,9 @@ } //---------------------------------------------------------------------------- - bool ODGauge::serviceable(void) + bool ODGauge::serviceable() const { - return rtAvailable; + return _flags & AVAILABLE; } //---------------------------------------------------------------------------- @@ -196,26 +242,25 @@ osg::PolygonMode::FILL ), osg::StateAttribute::ON ); stateSet->setAttributeAndModes( - new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.0f), + new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.001f), osg::StateAttribute::ON ); stateSet->setAttribute(new osg::ShadeModel(osg::ShadeModel::FLAT)); - stateSet->setAttributeAndModes( - new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA, - osg::BlendFunc::ONE_MINUS_SRC_ALPHA), - osg::StateAttribute::ON ); + if( !texture ) { texture = new osg::Texture2D; + texture->setResizeNonPowerOfTwoHint(false); texture->setTextureSize(_size_x, _size_y); texture->setInternalFormat(GL_RGBA); } updateSampling(); + updateBlendMode(); - if( _system_adapter ) - _system_adapter->addCamera(camera.get()); + if( Canvas::getSystemAdapter() ) + Canvas::getSystemAdapter()->addCamera(camera.get()); - rtAvailable = true; + _flags |= AVAILABLE; } //---------------------------------------------------------------------------- @@ -229,12 +274,22 @@ //---------------------------------------------------------------------------- void ODGauge::clear() { - if( camera.valid() && _system_adapter ) - _system_adapter->removeCamera(camera.get()); + if( camera.valid() && Canvas::getSystemAdapter() ) + Canvas::getSystemAdapter()->removeCamera(camera.get()); camera.release(); texture.release(); - rtAvailable = false; + _flags &= ~AVAILABLE; + } + + //---------------------------------------------------------------------------- + bool ODGauge::updateFlag(Flags flag, bool enable) + { + if( bool(_flags & flag) == enable ) + return false; + + _flags ^= flag; + return true; } //---------------------------------------------------------------------------- @@ -249,7 +304,7 @@ camera->setViewport(0, 0, _size_x, _size_y); - if( _use_image_coords ) + if( _flags & USE_IMAGE_COORDS ) camera->setProjectionMatrix( osg::Matrix::ortho2D(0, _view_width, _view_height, 0) ); @@ -267,7 +322,7 @@ GLbitfield mask = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; - if( _use_stencil) + if( _flags & USE_STENCIL ) { camera->attach( osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, GL_DEPTH_STENCIL_EXT ); @@ -289,18 +344,36 @@ texture->setFilter( osg::Texture2D::MIN_FILTER, - _use_mipmapping ? osg::Texture2D::LINEAR_MIPMAP_LINEAR - : osg::Texture2D::LINEAR + (_flags & USE_MIPMAPPING) ? osg::Texture2D::LINEAR_MIPMAP_LINEAR + : osg::Texture2D::LINEAR ); camera->attach( osg::Camera::COLOR_BUFFER, texture.get(), 0, 0, - _use_mipmapping, + _flags & USE_MIPMAPPING, _coverage_samples, _color_samples ); } + //---------------------------------------------------------------------------- + void ODGauge::updateBlendMode() + { + assert( camera ); + + camera->getOrCreateStateSet() + ->setAttributeAndModes + ( + (_flags & USE_ADDITIVE_BLEND) + ? new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA, + osg::BlendFunc::ONE_MINUS_SRC_ALPHA, + osg::BlendFunc::ONE, + osg::BlendFunc::ONE ) + : new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA, + osg::BlendFunc::ONE_MINUS_SRC_ALPHA ) + ); + } + } // namespace canvas } // namespace simgear diff -Nru simgear-2.10.0/simgear/canvas/ODGauge.hxx simgear-3.0.0/simgear/canvas/ODGauge.hxx --- simgear-2.10.0/simgear/canvas/ODGauge.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/ODGauge.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -53,8 +53,6 @@ ODGauge(); virtual ~ODGauge(); - void setSystemAdapter(const SystemAdapterPtr& system_adapter); - /** * Set the size of the render target. * @@ -71,6 +69,8 @@ */ void setViewSize(int width, int height = -1); + osg::Vec2s getViewSize() const; + /** * DEPRECATED * @@ -92,6 +92,12 @@ void useStencil(bool use = true); /** + * Enable/Disable additive alpha blending (Can improve results with + * transparent background) + */ + void useAdditiveBlend(bool use = true); + + /** * Set sampling parameters for mipmapping and coverage sampling * antialiasing. * @@ -112,7 +118,7 @@ * Say if we can render to a texture. * @return true if rtt is available */ - bool serviceable(void); + bool serviceable() const; /** * Get the OSG camera for drawing this gauge. @@ -128,27 +134,35 @@ protected: - SystemAdapterPtr _system_adapter; - int _size_x, _size_y, _view_width, _view_height; - bool _use_image_coords, - _use_stencil, - _use_mipmapping; + + enum Flags + { + AVAILABLE = 1, + USE_IMAGE_COORDS = AVAILABLE << 1, + USE_STENCIL = USE_IMAGE_COORDS << 1, + USE_MIPMAPPING = USE_STENCIL << 1, + USE_ADDITIVE_BLEND = USE_MIPMAPPING << 1 + }; + + uint32_t _flags; // Multisampling parameters int _coverage_samples, _color_samples; - bool rtAvailable; osg::ref_ptr camera; osg::ref_ptr texture; + bool updateFlag(Flags flag, bool enable); + void updateCoordinateFrame(); void updateStencil(); void updateSampling(); + void updateBlendMode(); }; diff -Nru simgear-2.10.0/simgear/canvas/ShivaVG/include/vg/openvg.h simgear-3.0.0/simgear/canvas/ShivaVG/include/vg/openvg.h --- simgear-2.10.0/simgear/canvas/ShivaVG/include/vg/openvg.h 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/ShivaVG/include/vg/openvg.h 2014-02-15 00:04:11.000000000 +0000 @@ -627,6 +627,7 @@ #define OVG_SH_blend_dst_atop 1 VG_API_CALL VGboolean vgCreateContextSH(VGint width, VGint height); +VG_API_CALL VGboolean vgHasContextSH(); VG_API_CALL void vgResizeSurfaceSH(VGint width, VGint height); VG_API_CALL void vgDestroyContextSH(void); diff -Nru simgear-2.10.0/simgear/canvas/ShivaVG/src/shContext.c simgear-3.0.0/simgear/canvas/ShivaVG/src/shContext.c --- simgear-2.10.0/simgear/canvas/ShivaVG/src/shContext.c 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/canvas/ShivaVG/src/shContext.c 2014-02-15 00:04:11.000000000 +0000 @@ -61,6 +61,11 @@ return VG_TRUE; } +VG_API_CALL VGboolean vgHasContextSH() +{ + return g_context != NULL; +} + VG_API_CALL void vgResizeSurfaceSH(VGint width, VGint height) { VG_GETCONTEXT(VG_NO_RETVAL); diff -Nru simgear-2.10.0/simgear/CMakeLists.txt simgear-3.0.0/simgear/CMakeLists.txt --- simgear-2.10.0/simgear/CMakeLists.txt 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -18,6 +18,7 @@ threads timing xml + package ) add_subdirectory(${mylibfolder}) @@ -44,52 +45,29 @@ get_property(coreSources GLOBAL PROPERTY CORE_SOURCES) get_property(sceneSources GLOBAL PROPERTY SCENE_SOURCES) get_property(publicHeaders GLOBAL PROPERTY PUBLIC_HEADERS) - -if(LIBSVN_FOUND) - add_definitions(${APR_CFLAGS}) - include_directories(${LIBSVN_INCLUDE_DIR}) -endif() +get_property(localExpatSources GLOBAL PROPERTY LOCAL_EXPAT_SOURCES) if(SIMGEAR_SHARED) message(STATUS "Library building mode: SHARED LIBRARIES") - add_library(SimGearCore SHARED ${coreSources}) + add_library(SimGearCore SHARED ${coreSources} ${localExpatSources}) - # set_property(TARGET SimGearCore PROPERTY FRAMEWORK 1) - # message(STATUS "public header: ${publicHeaders}") - # set_property(TARGET SimGearCore PROPERTY PUBLIC_HEADER "${publicHeaders}") set_property(TARGET SimGearCore PROPERTY LINKER_LANGUAGE CXX) - set_property(TARGET SimGearCore PROPERTY VERSION ${SIMGEAR_VERSION}) set_property(TARGET SimGearCore PROPERTY SOVERSION ${SIMGEAR_SOVERSION}) - - target_link_libraries(SimGearCore ${ZLIB_LIBRARY} ${RT_LIBRARY} - ${EXPAT_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT}) - - if(LIBSVN_FOUND) - target_link_libraries(SimGearCore ${LIBSVN_LIBRARIES}) - endif(LIBSVN_FOUND) - + install(TARGETS SimGearCore EXPORT SimGearCoreConfig LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(EXPORT SimGearCoreConfig DESTINATION share/SimGearCore) + if(NOT SIMGEAR_HEADLESS) add_library(SimGearScene SHARED ${sceneSources}) - # set_property(TARGET SimGearScene PROPERTY FRAMEWORK 1) - # set_property(TARGET SimGearScene PROPERTY PUBLIC_HEADER "${publicHeaders}") set_property(TARGET SimGearScene PROPERTY LINKER_LANGUAGE CXX) set_property(TARGET SimGearScene PROPERTY VERSION ${SIMGEAR_VERSION}) set_property(TARGET SimGearScene PROPERTY SOVERSION ${SIMGEAR_SOVERSION}) - target_link_libraries(SimGearScene - SimGearCore - ${ZLIB_LIBRARY} - ${OPENSCENEGRAPH_LIBRARIES} - ${OPENAL_LIBRARY} - ${OPENGL_LIBRARY} - ${JPEG_LIBRARY}) - - install(TARGETS SimGearScene LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + # EXPORT SimGearSceneConfig + install(TARGETS SimGearScene LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ) + # install(EXPORT SimGearSceneConfig DESTINATION share/SimGearScene) endif() - install(TARGETS SimGearCore LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) else() message(STATUS "Library building mode: STATIC LIBRARIES") @@ -111,7 +89,7 @@ source_group("${name}\\Headers" FILES ${g2}) endforeach() - add_library(SimGearCore STATIC ${coreSources}) + add_library(SimGearCore STATIC ${coreSources} ${localExpatSources}) install(TARGETS SimGearCore ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) if(NOT SIMGEAR_HEADLESS) @@ -138,6 +116,24 @@ endif(NOT SIMGEAR_HEADLESS) endif(SIMGEAR_SHARED) +target_link_libraries(SimGearCore + ${ZLIB_LIBRARY} + ${RT_LIBRARY} + ${DL_LIBRARY} + ${EXPAT_LIBRARIES} + ${CMAKE_THREAD_LIBS_INIT} + ${CORE_SERVICES_LIBRARY}) + +if(NOT SIMGEAR_HEADLESS) + target_link_libraries(SimGearScene + SimGearCore + ${ZLIB_LIBRARY} + ${OPENSCENEGRAPH_LIBRARIES} + ${OPENAL_LIBRARY} + ${OPENGL_LIBRARY} + ${JPEG_LIBRARY}) +endif() + if(ENABLE_RTI) # Ugly first aid to make hla compile agian set_property(SOURCE hla/RTI13InteractionClass.cxx hla/RTI13ObjectClass.cxx diff -Nru simgear-2.10.0/simgear/compiler.h simgear-3.0.0/simgear/compiler.h --- simgear-2.10.0/simgear/compiler.h 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/compiler.h 2014-02-15 00:04:11.000000000 +0000 @@ -46,7 +46,7 @@ # warning GCC compilers prior to 3.4 are suspect # endif -# define GCC_VERSION (__GNUC__ * 10000 \ +# define SG_GCC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) # define SG_COMPILER_STR "GNU C++ version " SG_STRINGIZE(__GNUC__) "." SG_STRINGIZE(__GNUC_MINOR__) diff -Nru simgear-2.10.0/simgear/constants.h simgear-3.0.0/simgear/constants.h --- simgear-2.10.0/simgear/constants.h 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/constants.h 2014-02-15 00:04:11.000000000 +0000 @@ -1,6 +1,7 @@ // constants.h -- various constant definitions // // Written by Curtis Olson, started February 2000. +// Last change by Eric van den Berg, Feb 2013 // // Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt/ // @@ -103,6 +104,37 @@ /** Radius squared (meter) */ #define SG_EQ_RAD_SQUARE_M 40680645877797.1344 + +// Physical Constants, SI + +/**mean gravity on earth */ +#define SG_g0_m_p_s2 9.80665 // m/s2 + +/**standard pressure at SL */ +#define SG_p0_Pa 101325.0 // Pa + +/**standard density at SL */ +#define SG_rho0_kg_p_m3 1.225 // kg/m3 + +/**standard temperature at SL */ +#define SG_T0_K 288.15 // K (=15degC) + +/**specific gas constant of air*/ +#define SG_R_m2_p_s2_p_K 287.05 // m2/s2/K + +/**specific heat constant at constant pressure*/ +#define SG_cp_m2_p_s2_p_K 1004.68 // m2/s2/K + +/**ratio of specific heats of air*/ +#define SG_gamma 1.4 // =cp/cv (cp = 1004.68 m2/s2 K , cv = 717.63 m2/s2 K) + +/**constant beta used to calculate dynamic viscosity */ +#define SG_beta_kg_p_sm_sqrK 1.458e-06 // kg/s/m/SQRT(K) + +/** Sutherland constant */ +#define SG_S_K 110.4 // K + + // Conversions /** Arc seconds to radians. (arcsec*pi)/(3600*180) = rad */ @@ -165,6 +197,9 @@ /** Inch Mercury to Pascal */ #define SG_INHG_TO_PA 3386.388640341 +/** slug/ft3 to kg/m3 */ +#define SG_SLUGFT3_TO_KGPM3 515.379 + /** For divide by zero avoidance, this will be close enough to zero */ #define SG_EPSILON 0.0000001 diff -Nru simgear-2.10.0/simgear/debug/BufferedLogCallback.cxx simgear-3.0.0/simgear/debug/BufferedLogCallback.cxx --- simgear-2.10.0/simgear/debug/BufferedLogCallback.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/debug/BufferedLogCallback.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,98 @@ +/** \file BufferedLogCallback.cxx + * Buffer certain log messages permanently for later retrieval and display + */ + +// Copyright (C) 2013 James Turner zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include + +#include + +#include +#include +#include + +namespace simgear +{ + +class BufferedLogCallback::BufferedLogCallbackPrivate +{ +public: + SGMutex m_mutex; + vector_cstring m_buffer; + unsigned int m_stamp; + unsigned int m_maxLength; +}; + +BufferedLogCallback::BufferedLogCallback(sgDebugClass c, sgDebugPriority p) : + simgear::LogCallback(c,p), + d(new BufferedLogCallbackPrivate) +{ + d->m_stamp = 0; + d->m_maxLength = 0xffff; +} + +BufferedLogCallback::~BufferedLogCallback() +{ + BOOST_FOREACH(unsigned char* msg, d->m_buffer) { + free(msg); + } +} + +void BufferedLogCallback::operator()(sgDebugClass c, sgDebugPriority p, + const char* file, int line, const std::string& aMessage) +{ + SG_UNUSED(file); + SG_UNUSED(line); + + if (!shouldLog(c, p)) return; + + vector_cstring::value_type msg; + if (aMessage.size() >= d->m_maxLength) { + msg = (vector_cstring::value_type) malloc(d->m_maxLength); + strncpy((char*) msg, aMessage.c_str(), d->m_maxLength - 1); + msg[d->m_maxLength - 1] = 0; // add final NULL byte + } else { + msg = (vector_cstring::value_type) strdup(aMessage.c_str()); + } + + SGGuard g(d->m_mutex); + d->m_buffer.push_back(msg); + d->m_stamp++; +} + +unsigned int BufferedLogCallback::stamp() const +{ + return d->m_stamp; +} + +unsigned int BufferedLogCallback::threadsafeCopy(vector_cstring& aOutput) +{ + SGGuard g(d->m_mutex); + size_t sz = d->m_buffer.size(); + aOutput.resize(sz); + memcpy(aOutput.data(), d->m_buffer.data(), sz * sizeof(vector_cstring::value_type)); + return d->m_stamp; +} + +void BufferedLogCallback::truncateAt(unsigned int t) +{ + d->m_maxLength = t; +} + +} // of namespace simgear diff -Nru simgear-2.10.0/simgear/debug/BufferedLogCallback.hxx simgear-3.0.0/simgear/debug/BufferedLogCallback.hxx --- simgear-2.10.0/simgear/debug/BufferedLogCallback.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/debug/BufferedLogCallback.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,79 @@ +/** \file BufferedLogCallback.hxx + * Buffer certain log messages permanently for later retrieval and display + */ + +// Copyright (C) 2013 James Turner zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + + +#ifndef SG_DEBUG_BUFFEREDLOGCALLBACK_HXX +#define SG_DEBUG_BUFFEREDLOGCALLBACK_HXX + +#include +#include // for std::auto_ptr + +#include + +namespace simgear +{ + +class BufferedLogCallback : public LogCallback +{ +public: + BufferedLogCallback(sgDebugClass c, sgDebugPriority p); + virtual ~BufferedLogCallback(); + + /// truncate messages longer than a certain length. This is to work-around + /// for broken PUI behaviour, it can be removed once PUI is gone. + void truncateAt(unsigned int); + + virtual void operator()(sgDebugClass c, sgDebugPriority p, + const char* file, int line, const std::string& aMessage); + + /** + * read the stamp value associated with the log buffer. This is + * incremented whenever the log contents change, so can be used + * to poll for changes. + */ + unsigned int stamp() const; + + /** + * copying a (large) vector of std::string would be very expensive. + * once logged, this call retains storage of the underlying string data, + * so when copying, it's sufficient to pass around the strings as raw + * char arrays. This means we're only copying a vector of pointers, + * which is very efficient. + */ + typedef std::vector vector_cstring; + + /** + * copy the buffered log data into the provided output list + * (which will be cleared first). This method is safe to call from + * any thread. + * + * returns the stamp value of the copied data + */ + unsigned int threadsafeCopy(vector_cstring& aOutput); +private: + class BufferedLogCallbackPrivate; + std::auto_ptr d; +}; + + +} // of namespace simgear + +#endif // of SG_DEBUG_BUFFEREDLOGCALLBACK_HXX \ No newline at end of file diff -Nru simgear-2.10.0/simgear/debug/CMakeLists.txt simgear-3.0.0/simgear/debug/CMakeLists.txt --- simgear-2.10.0/simgear/debug/CMakeLists.txt 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/debug/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -1,7 +1,7 @@ include (SimGearComponent) -set(HEADERS debug_types.h logstream.hxx) -set(SOURCES logstream.cxx) +set(HEADERS debug_types.h logstream.hxx BufferedLogCallback.hxx) +set(SOURCES logstream.cxx BufferedLogCallback.cxx) simgear_component(debug debug "${SOURCES}" "${HEADERS}") \ No newline at end of file diff -Nru simgear-2.10.0/simgear/debug/logstream.cxx simgear-3.0.0/simgear/debug/logstream.cxx --- simgear-2.10.0/simgear/debug/logstream.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/debug/logstream.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -20,95 +20,422 @@ // // $Id$ -#include +#include #include "logstream.hxx" -logstream *logstream::global_logstream = 0; +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#ifdef SG_WINDOWS +// for AllocConsole, OutputDebugString + #include "windows.h" +#endif + +const char* debugClassToString(sgDebugClass c) +{ + switch (c) { + case SG_NONE: return "none"; + case SG_TERRAIN: return "terrain"; + case SG_ASTRO: return "astro"; + case SG_FLIGHT: return "flight"; + case SG_INPUT: return "input"; + case SG_GL: return "opengl"; + case SG_VIEW: return "view"; + case SG_COCKPIT: return "cockpit"; + case SG_GENERAL: return "general"; + case SG_MATH: return "math"; + case SG_EVENT: return "event"; + case SG_AIRCRAFT: return "aircraft"; + case SG_AUTOPILOT: return "autopilot"; + case SG_IO: return "io"; + case SG_CLIPPER: return "clipper"; + case SG_NETWORK: return "network"; + case SG_ATC: return "atc"; + case SG_NASAL: return "nasal"; + case SG_INSTR: return "instruments"; + case SG_SYSTEMS: return "systems"; + case SG_AI: return "ai"; + case SG_ENVIRONMENT:return "environment"; + case SG_SOUND: return "sound"; + case SG_NAVAID: return "navaid"; + default: return "unknown"; + } +} + +////////////////////////////////////////////////////////////////////////////// + +namespace simgear +{ -bool logbuf::logging_enabled = true; -#ifdef _WIN32 - bool logbuf::has_console = true; +LogCallback::LogCallback(sgDebugClass c, sgDebugPriority p) : + m_class(c), + m_priority(p) +{ +} + +bool LogCallback::shouldLog(sgDebugClass c, sgDebugPriority p) const +{ + return ((c & m_class) != 0 && p >= m_priority); +} + +void LogCallback::setLogLevels( sgDebugClass c, sgDebugPriority p ) +{ + m_priority = p; + m_class = c; +} + +} // of namespace simgear + +////////////////////////////////////////////////////////////////////////////// + +class FileLogCallback : public simgear::LogCallback +{ +public: + FileLogCallback(const std::string& aPath, sgDebugClass c, sgDebugPriority p) : + simgear::LogCallback(c, p), + m_file(aPath.c_str(), std::ios_base::out | std::ios_base::trunc) + { + } + + virtual void operator()(sgDebugClass c, sgDebugPriority p, + const char* file, int line, const std::string& message) + { + if (!shouldLog(c, p)) return; + m_file << debugClassToString(c) << ":" << (int) p + << ":" << file << ":" << line << ":" << message << std::endl; + } +private: + std::ofstream m_file; +}; + +class StderrLogCallback : public simgear::LogCallback +{ +public: + StderrLogCallback(sgDebugClass c, sgDebugPriority p) : + simgear::LogCallback(c, p) + { +#ifdef SG_WINDOWS + AllocConsole(); // but only if we want a console + freopen("conin$", "r", stdin); + freopen("conout$", "w", stdout); + freopen("conout$", "w", stderr); #endif -sgDebugClass logbuf::logClass = SG_NONE; -sgDebugPriority logbuf::logPriority = SG_INFO; -streambuf* logbuf::sbuf = NULL; + } + + virtual void operator()(sgDebugClass c, sgDebugPriority p, + const char* file, int line, const std::string& aMessage) + { + if (!shouldLog(c, p)) return; + + fprintf(stderr, "%s\n", aMessage.c_str()); + //fprintf(stderr, "%s:%d:%s:%d:%s\n", debugClassToString(c), p, + // file, line, aMessage.c_str()); + fflush(stderr); + } +}; + -namespace { -struct ignore_me +#ifdef SG_WINDOWS + +class WinDebugLogCallback : public simgear::LogCallback { - ignore_me() +public: + WinDebugLogCallback(sgDebugClass c, sgDebugPriority p) : + simgear::LogCallback(c, p) + { + } + + virtual void operator()(sgDebugClass c, sgDebugPriority p, + const char* file, int line, const std::string& aMessage) { - logstream::initGlobalLogstream(); + if (!shouldLog(c, p)) return; + + std::ostringstream os; + os << debugClassToString(c) << ":" << aMessage << std::endl; + OutputDebugStringA(os.str().c_str()); } }; -static ignore_me im; -} -logbuf::logbuf() +#endif + +class LogStreamPrivate : public SGThread { -// if ( sbuf == NULL ) -// sbuf = cerr.rdbuf(); -} +private: + /** + * storage of a single log entry. Note this is not used for a persistent + * store, but rather for short term buffering between the submitting + * and output threads. + */ + class LogEntry + { + public: + LogEntry(sgDebugClass c, sgDebugPriority p, + const char* f, int l, const std::string& msg) : + debugClass(c), debugPriority(p), file(f), line(l), + message(msg) + { + } + + sgDebugClass debugClass; + sgDebugPriority debugPriority; + const char* file; + int line; + std::string message; + }; + + class PauseThread + { + public: + PauseThread(LogStreamPrivate* parent) : m_parent(parent) + { + m_wasRunning = m_parent->stop(); + } + + ~PauseThread() + { + if (m_wasRunning) { + m_parent->startLog(); + } + } + private: + LogStreamPrivate* m_parent; + bool m_wasRunning; + }; +public: + LogStreamPrivate() : + m_logClass(SG_ALL), + m_logPriority(SG_ALERT), + m_isRunning(false), + m_consoleRequested(false) + { + +#if !defined(SG_WINDOWS) + m_callbacks.push_back(new StderrLogCallback(m_logClass, m_logPriority)); + m_consoleCallbacks.push_back(m_callbacks.back()); + m_consoleRequested = true; +#endif -logbuf::~logbuf() +#if defined (SG_WINDOWS) && !defined(NDEBUG) + m_callbacks.push_back(new WinDebugLogCallback(m_logClass, m_logPriority)); + m_consoleCallbacks.push_back(m_callbacks.back()); +#endif + } + + SGMutex m_lock; + SGBlockingQueue m_entries; + + typedef std::vector CallbackVec; + CallbackVec m_callbacks; + /// subset of callbacks which correspond to stdout / console, + /// and hence should dynamically reflect console logging settings + CallbackVec m_consoleCallbacks; + + sgDebugClass m_logClass; + sgDebugPriority m_logPriority; + bool m_isRunning; + bool m_consoleRequested; + + void startLog() + { + SGGuard g(m_lock); + if (m_isRunning) return; + m_isRunning = true; + start(); + } + + virtual void run() + { + while (1) { + LogEntry entry(m_entries.pop()); + // special marker entry detected, terminate the thread since we are + // making a configuration change or quitting the app + if ((entry.debugClass == SG_NONE) && !strcmp(entry.file, "done")) { + return; + } + + // submit to each installed callback in turn + BOOST_FOREACH(simgear::LogCallback* cb, m_callbacks) { + (*cb)(entry.debugClass, entry.debugPriority, + entry.file, entry.line, entry.message); + } + } // of main thread loop + } + + bool stop() + { + SGGuard g(m_lock); + if (!m_isRunning) { + return false; + } + + // log a special marker value, which will cause the thread to wakeup, + // and then exit + log(SG_NONE, SG_ALERT, "done", -1, ""); + join(); + + m_isRunning = false; + return true; + } + + void addCallback(simgear::LogCallback* cb) + { + PauseThread pause(this); + m_callbacks.push_back(cb); + } + + void removeCallback(simgear::LogCallback* cb) + { + PauseThread pause(this); + CallbackVec::iterator it = std::find(m_callbacks.begin(), m_callbacks.end(), cb); + if (it != m_callbacks.end()) { + m_callbacks.erase(it); + } + } + + void setLogLevels( sgDebugClass c, sgDebugPriority p ) + { + PauseThread pause(this); + m_logPriority = p; + m_logClass = c; + BOOST_FOREACH(simgear::LogCallback* cb, m_consoleCallbacks) { + cb->setLogLevels(c, p); + } + } + + bool would_log( sgDebugClass c, sgDebugPriority p ) const + { + if (p >= SG_INFO) return true; + return ((c & m_logClass) != 0 && p >= m_logPriority); + } + + void log( sgDebugClass c, sgDebugPriority p, + const char* fileName, int line, const std::string& msg) + { + LogEntry entry(c, p, fileName, line, msg); + m_entries.push(entry); + } + + void requestConsole() + { + PauseThread pause(this); + if (m_consoleRequested) { + return; + } + + m_consoleRequested = true; + m_callbacks.push_back(new StderrLogCallback(m_logClass, m_logPriority)); + m_consoleCallbacks.push_back(m_callbacks.back()); + } +}; + +///////////////////////////////////////////////////////////////////////////// + +static logstream* global_logstream = NULL; +static LogStreamPrivate* global_privateLogstream = NULL; + +logstream::logstream() { - if ( sbuf ) - sync(); + global_privateLogstream = new LogStreamPrivate; + global_privateLogstream->startLog(); } void -logbuf::set_sb( streambuf* sb ) +logstream::setLogLevels( sgDebugClass c, sgDebugPriority p ) { - if ( sbuf ) - sync(); + global_privateLogstream->setLogLevels(c, p); +} - sbuf = sb; +void +logstream::addCallback(simgear::LogCallback* cb) +{ + global_privateLogstream->addCallback(cb); } void -logbuf::set_log_level( sgDebugClass c, sgDebugPriority p ) -{ - logClass = c; - logPriority = p; +logstream::removeCallback(simgear::LogCallback* cb) +{ + global_privateLogstream->removeCallback(cb); } void -logbuf::set_log_classes (sgDebugClass c) +logstream::log( sgDebugClass c, sgDebugPriority p, + const char* fileName, int line, const std::string& msg) { - logClass = c; + global_privateLogstream->log(c, p, fileName, line, msg); } -sgDebugClass -logbuf::get_log_classes () +bool +logstream::would_log( sgDebugClass c, sgDebugPriority p ) const { - return logClass; + return global_privateLogstream->would_log(c,p); } -void -logbuf::set_log_priority (sgDebugPriority p) +sgDebugClass +logstream::get_log_classes() const { - logPriority = p; + return global_privateLogstream->m_logClass; } - + sgDebugPriority -logbuf::get_log_priority () +logstream::get_log_priority() const { - return logPriority; + return global_privateLogstream->m_logPriority; } void -logstream::setLogLevels( sgDebugClass c, sgDebugPriority p ) +logstream::set_log_priority( sgDebugPriority p) +{ + global_privateLogstream->setLogLevels(global_privateLogstream->m_logClass, p); +} + +void +logstream::set_log_classes( sgDebugClass c) { - logbuf::set_log_level( c, p ); + global_privateLogstream->setLogLevels(c, global_privateLogstream->m_logPriority); } -logstream * -logstream::initGlobalLogstream() +logstream& +sglog() { // Force initialization of cerr. static std::ios_base::Init initializer; + + // http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf + // in the absence of portable memory barrier ops in Simgear, + // let's keep this correct & safe + static SGMutex m; + SGGuard g(m); + if( !global_logstream ) - global_logstream = new logstream(std::cerr); - return global_logstream; + global_logstream = new logstream(); + return *global_logstream; +} + +void +logstream::logToFile( const SGPath& aPath, sgDebugClass c, sgDebugPriority p ) +{ + global_privateLogstream->addCallback(new FileLogCallback(aPath.str(), c, p)); } + +namespace simgear +{ + +void requestConsole() +{ + sglog(); // force creation + global_privateLogstream->requestConsole(); +} + +} // of namespace simgear \ No newline at end of file diff -Nru simgear-2.10.0/simgear/debug/logstream.hxx simgear-3.0.0/simgear/debug/logstream.hxx --- simgear-2.10.0/simgear/debug/logstream.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/debug/logstream.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -26,222 +26,49 @@ #define _LOGSTREAM_H #include - -#ifdef _WIN32 -# include -#endif - -#include -#include -#include - #include -using std::streambuf; -using std::ostream; - -// -// TODO: -// -// 1. Change output destination. Done. -// 2. Make logbuf thread safe. -// 3. Read environment for default debugClass and debugPriority. -// - -/** - * logbuf is an output-only streambuf with the ability to disable sets of - * messages at runtime. Only messages with priority >= logbuf::logPriority - * and debugClass == logbuf::logClass are output. - */ -#ifdef SG_NEED_STREAMBUF_HACK -class logbuf : public __streambuf -#else -class logbuf : public std::streambuf -#endif +#include + +// forward decls +class SGPath; + +namespace simgear +{ + +class LogCallback { public: - // logbuf( streambuf* sb ) : sbuf(sb) {} - /** Constructor */ - logbuf(); - - /** Destructor */ - ~logbuf(); - - /** - * Is logging enabled? - * @return true or false*/ - bool enabled() { return logging_enabled; } - - /** - * Set the logging level of subsequent messages. - * @param c debug class - * @param p priority - */ - void set_log_state( sgDebugClass c, sgDebugPriority p ); - - bool would_log( sgDebugClass c, sgDebugPriority p ) const; - - /** - * Set the global logging level. - * @param c debug class - * @param p priority - */ - static void set_log_level( sgDebugClass c, sgDebugPriority p ); - - - /** - * Set the allowed logging classes. - * @param c All enabled logging classes anded together. - */ - static void set_log_classes (sgDebugClass c); - - - /** - * Get the logging classes currently enabled. - * @return All enabled debug logging anded together. - */ - static sgDebugClass get_log_classes (); - - - /** - * Set the logging priority. - * @param c The priority cutoff for logging messages. - */ - static void set_log_priority (sgDebugPriority p); - - - /** - * Get the current logging priority. - * @return The priority cutoff for logging messages. - */ - static sgDebugPriority get_log_priority (); - - - /** - * Set the stream buffer - * @param sb stream buffer - */ - void set_sb( std::streambuf* sb ); - -#ifdef _WIN32 - static void has_no_console() { has_console = false; } -#endif + virtual ~LogCallback() {} + virtual void operator()(sgDebugClass c, sgDebugPriority p, + const char* file, int line, const std::string& aMessage) = 0; + void setLogLevels(sgDebugClass c, sgDebugPriority p); protected: + LogCallback(sgDebugClass c, sgDebugPriority p); - /** sync/flush */ - inline virtual int sync(); - - /** overflow */ - int_type overflow( int ch ); - // int xsputn( const char* s, istreamsize n ); - -private: - - // The streambuf used for actual output. Defaults to cerr.rdbuf(). - static std::streambuf* sbuf; - - static bool logging_enabled; -#ifdef _WIN32 - static bool has_console; -#endif - static sgDebugClass logClass; - static sgDebugPriority logPriority; - + bool shouldLog(sgDebugClass c, sgDebugPriority p) const; private: - - // Not defined. - logbuf( const logbuf& ); - void operator= ( const logbuf& ); -}; - -inline int -logbuf::sync() -{ - return sbuf->pubsync(); -} - -inline void -logbuf::set_log_state( sgDebugClass c, sgDebugPriority p ) -{ - logging_enabled = ((c & logClass) != 0 && p >= logPriority); -} - -inline bool -logbuf::would_log( sgDebugClass c, sgDebugPriority p ) const -{ - return ((c & logClass) != 0 && p >= logPriority); -} - -inline logbuf::int_type -logbuf::overflow( int c ) -{ -#ifdef _WIN32 - if ( logging_enabled ) { - if ( !has_console ) { - AllocConsole(); - freopen("conin$", "r", stdin); - freopen("conout$", "w", stdout); - freopen("conout$", "w", stderr); - has_console = true; - } - return sbuf->sputc(c); - } - else - return EOF == 0 ? 1: 0; -#else - return logging_enabled ? sbuf->sputc(c) : (EOF == 0 ? 1: 0); -#endif -} - -/** - * logstream manipulator for setting the log level of a message. - */ -struct loglevel -{ - loglevel( sgDebugClass c, sgDebugPriority p ) - : logClass(c), logPriority(p) {} - - sgDebugClass logClass; - sgDebugPriority logPriority; + sgDebugClass m_class; + sgDebugPriority m_priority; }; /** - * A helper class that ensures a streambuf and ostream are constructed and - * destroyed in the correct order. The streambuf must be created before the - * ostream but bases are constructed before members. Thus, making this class - * a private base of logstream, declared to the left of ostream, we ensure the - * correct order of construction and destruction. - */ -struct logstream_base -{ - // logstream_base( streambuf* sb ) : lbuf(sb) {} - logstream_base() {} - - logbuf lbuf; -}; + * Helper force a console on platforms where it might optional, when + * we need to show a console. This basically means Windows at the + * moment - on other plaforms it's a no-op + */ +void requestConsole(); + +} // of namespace simgear /** * Class to manage the debug logging stream. */ -class logstream : private logstream_base, public std::ostream +class logstream { public: - /** - * The default is to send messages to cerr. - * @param out output stream - */ - logstream( std::ostream& out ) - // : logstream_base(out.rdbuf()), - : logstream_base(), - std::ostream(&lbuf) { lbuf.set_sb(out.rdbuf());} - - /** - * Set the output stream - * @param out output stream - */ - void set_output( std::ostream& out ) { lbuf.set_sb( out.rdbuf() ); } - + static void initGlobalLogstream(); /** * Set the global log class and priority level. * @param c debug class @@ -249,41 +76,49 @@ */ void setLogLevels( sgDebugClass c, sgDebugPriority p ); - bool would_log( sgDebugClass c, sgDebugPriority p ) const - { - return lbuf.would_log( c, p ); - }; + bool would_log( sgDebugClass c, sgDebugPriority p ) const; - /** - * Output operator to capture the debug level and priority of a message. - * @param l log level - */ - inline std::ostream& operator<< ( const loglevel& l ); + void logToFile( const SGPath& aPath, sgDebugClass c, sgDebugPriority p ); + + void set_log_priority( sgDebugPriority p); + + void set_log_classes( sgDebugClass c); + + sgDebugClass get_log_classes() const; + + sgDebugPriority get_log_priority() const; + + /** + * the core logging method + */ + void log( sgDebugClass c, sgDebugPriority p, + const char* fileName, int line, const std::string& msg); + + /** + * \relates logstream + * Return the one and only logstream instance. + * We use a function instead of a global object so we are assured that cerr + * has been initialised. + * @return current logstream + */ friend logstream& sglog(); - static logstream *initGlobalLogstream(); -protected: - static logstream *global_logstream; + + /** + * register a logging callback. Note callbacks are run in a + * dedicated thread, so callbacks which pass data to other threads + * must use appropriate locking. + */ + void addCallback(simgear::LogCallback* cb); + + void removeCallback(simgear::LogCallback* cb); + +private: + // constructor + logstream(); }; -inline std::ostream& -logstream::operator<< ( const loglevel& l ) -{ - lbuf.set_log_state( l.logClass, l.logPriority ); - return *this; -} +logstream& sglog(); -/** - * \relates logstream - * Return the one and only logstream instance. - * We use a function instead of a global object so we are assured that cerr - * has been initialised. - * @return current logstream - */ -inline logstream& -sglog() -{ - return *logstream::initGlobalLogstream(); -} /** \def SG_LOG(C,P,M) @@ -296,10 +131,12 @@ # define SG_LOG(C,P,M) #else # define SG_LOG(C,P,M) do { \ - logstream& __tmplogstreamref(sglog()); \ - if(__tmplogstreamref.would_log(C,P)) { \ - __tmplogstreamref << loglevel(C,P) << M << std::endl; } \ - } while(0) + if(sglog().would_log(C,P)) { \ + std::ostringstream os; \ + os << M; \ + sglog().log(C, P, __FILE__, __LINE__, os.str()); \ + } \ +} while(0) #endif #define SG_ORIGIN __FILE__ ":" SG_STRINGIZE(__LINE__) diff -Nru simgear-2.10.0/simgear/environment/metar.cxx simgear-3.0.0/simgear/environment/metar.cxx --- simgear-2.10.0/simgear/environment/metar.cxx 2011-10-24 11:45:21.000000000 +0000 +++ simgear-3.0.0/simgear/environment/metar.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -629,7 +629,7 @@ weather = pre + weather + post; weather.erase(weather.length() - 1); _weather.push_back(weather); - if( w.phenomena.size() > 0 ) + if( ! w.phenomena.empty() ) _weather2.push_back( w ); _grpcount++; return true; diff -Nru simgear-2.10.0/simgear/environment/precipitation.hxx simgear-3.0.0/simgear/environment/precipitation.hxx --- simgear-2.10.0/simgear/environment/precipitation.hxx 2011-05-09 11:58:18.000000000 +0000 +++ simgear-3.0.0/simgear/environment/precipitation.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -42,7 +42,6 @@ float _rain_intensity; float _clip_distance; - int _wind_dir; osg::Vec3 _wind_vec; osg::ref_ptr _precipitationEffect; diff -Nru simgear-2.10.0/simgear/io/CMakeLists.txt simgear-3.0.0/simgear/io/CMakeLists.txt --- simgear-2.10.0/simgear/io/CMakeLists.txt 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/io/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -15,7 +15,14 @@ sg_socket.hxx sg_socket_udp.hxx HTTPClient.hxx + HTTPFileRequest.hxx + HTTPMemoryRequest.hxx HTTPRequest.hxx + HTTPContentDecode.hxx + DAVMultiStatus.hxx + SVNRepository.hxx + SVNDirectory.hxx + SVNReportParser.hxx ) set(SOURCES @@ -31,22 +38,22 @@ sg_socket.cxx sg_socket_udp.cxx HTTPClient.cxx + HTTPFileRequest.cxx + HTTPMemoryRequest.cxx HTTPRequest.cxx + HTTPContentDecode.cxx + DAVMultiStatus.cxx + SVNRepository.cxx + SVNDirectory.cxx + SVNReportParser.cxx ) simgear_component(io io "${SOURCES}" "${HEADERS}") if(ENABLE_TESTS) -if (SIMGEAR_SHARED) - set(TEST_LIBS SimGearCore) -else() - set(TEST_LIBS SimGearCore - ${CMAKE_THREAD_LIBS_INIT} - ${WINSOCK_LIBRARY} - ${ZLIB_LIBRARY} - ${RT_LIBRARY}) -endif() +add_executable(http_svn http_svn.cxx) +target_link_libraries(http_svn ${TEST_LIBS}) add_executable(test_sock socktest.cxx) target_link_libraries(test_sock ${TEST_LIBS}) @@ -66,4 +73,5 @@ target_link_libraries(test_binobj ${TEST_LIBS}) add_test(binobj ${EXECUTABLE_OUTPUT_PATH}/test_binobj) + endif(ENABLE_TESTS) diff -Nru simgear-2.10.0/simgear/io/DAVMultiStatus.cxx simgear-3.0.0/simgear/io/DAVMultiStatus.cxx --- simgear-2.10.0/simgear/io/DAVMultiStatus.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/DAVMultiStatus.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,402 @@ +// DAVMultiStatus.cxx -- parser for WebDAV MultiStatus XML data +// +// Copyright (C) 2012 James Turner +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "DAVMultiStatus.hxx" + +#include +#include +#include +#include +#include + +#include + +#include "simgear/debug/logstream.hxx" +#include "simgear/misc/strutils.hxx" +#include "simgear/structure/exception.hxx" + +#ifdef SYSTEM_EXPAT +# include +#else +# include "sg_expat.h" +#endif + +using std::string; + +using namespace simgear; + +#define DAV_NS "DAV::" +#define SUBVERSION_DAV_NS "http://subversion.tigris.org/xmlns/dav/" + +const char* DAV_MULTISTATUS_TAG = DAV_NS "multistatus"; +const char* DAV_RESPONSE_TAG = DAV_NS "response"; +const char* DAV_PROPSTAT_TAG = DAV_NS "propstat"; +const char* DAV_PROP_TAG = DAV_NS "prop"; + +const char* DAV_HREF_TAG = DAV_NS "href"; +const char* DAV_RESOURCE_TYPE_TAG = DAV_NS "resourcetype"; +const char* DAV_CONTENT_TYPE_TAG = DAV_NS "getcontenttype"; +const char* DAV_CONTENT_LENGTH_TAG = DAV_NS "getcontentlength"; +const char* DAV_VERSIONNAME_TAG = DAV_NS "version-name"; +const char* DAV_COLLECTION_TAG = DAV_NS "collection"; +const char* DAV_VCC_TAG = DAV_NS "version-controlled-configuration"; + +const char* SUBVERSION_MD5_CHECKSUM_TAG = SUBVERSION_DAV_NS ":md5-checksum"; + +DAVResource::DAVResource(const string& href) : + _type(Unknown), + _url(href), + _container(NULL) +{ + assert(!href.empty()); + if (strutils::ends_with(href, "/")) { + _url = href.substr(0, _url.size() - 1); + } +} + +void DAVResource::setVersionName(const std::string& aVersion) +{ + _versionName = aVersion; +} + +void DAVResource::setVersionControlledConfiguration(const std::string& vcc) +{ + _vcc = vcc; +} + +void DAVResource::setMD5(const std::string& md5Hex) +{ + _md5 = md5Hex; +} + +std::string DAVResource::name() const +{ + string::size_type index = _url.rfind('/'); + if (index != string::npos) { + return _url.substr(index + 1); + } + + throw sg_exception("bad DAV resource HREF:" + _url); +} + +//////////////////////////////////////////////////////////////////////////// + +DAVCollection::DAVCollection(const string& href) : + DAVResource(href) +{ + _type = DAVResource::Collection; +} + +DAVCollection::~DAVCollection() +{ + BOOST_FOREACH(DAVResource* c, _contents) { + delete c; + } +} + +void DAVCollection::addChild(DAVResource *res) +{ + assert(res); + if (res->container() == this) { + return; + } + + assert(res->container() == NULL); + assert(std::find(_contents.begin(), _contents.end(), res) == _contents.end()); + assert(strutils::starts_with(res->url(), _url)); + assert(childWithUrl(res->url()) == NULL); + + res->_container = this; + _contents.push_back(res); +} + +void DAVCollection::removeChild(DAVResource* res) +{ + assert(res); + assert(res->container() == this); + + res->_container = NULL; + DAVResourceList::iterator it = std::find(_contents.begin(), _contents.end(), res); + assert(it != _contents.end()); + _contents.erase(it); +} + +DAVCollection* +DAVCollection::createChildCollection(const std::string& name) +{ + DAVCollection* child = new DAVCollection(urlForChildWithName(name)); + addChild(child); + return child; +} + +DAVResourceList DAVCollection::contents() const +{ + return _contents; +} + +DAVResource* DAVCollection::childWithUrl(const string& url) const +{ + if (url.empty()) + return NULL; + + BOOST_FOREACH(DAVResource* c, _contents) { + if (c->url() == url) { + return c; + } + } + + return NULL; +} + +DAVResource* DAVCollection::childWithName(const string& name) const +{ + return childWithUrl(urlForChildWithName(name)); +} + +std::string DAVCollection::urlForChildWithName(const std::string& name) const +{ + return url() + "/" + name; +} + +/////////////////////////////////////////////////////////////////////////////// + +class DAVMultiStatus::DAVMultiStatusPrivate +{ +public: + DAVMultiStatusPrivate() : + parserInited(false), + valid(false) + { + rootResource = NULL; + } + + void startElement (const char * name) + { + if (tagStack.empty()) { + if (strcmp(name, DAV_MULTISTATUS_TAG)) { + SG_LOG(SG_IO, SG_WARN, "root element is not " << + DAV_MULTISTATUS_TAG << ", got:" << name); + } else { + + } + } else { + // not at the root element + if (tagStack.back() == DAV_MULTISTATUS_TAG) { + if (strcmp(name, DAV_RESPONSE_TAG)) { + SG_LOG(SG_IO, SG_WARN, "multistatus child is not response: saw:" + << name); + } + } + + if (tagStack.back() == DAV_RESOURCE_TYPE_TAG) { + if (!strcmp(name, DAV_COLLECTION_TAG)) { + currentElementType = DAVResource::Collection; + } else { + currentElementType = DAVResource::Unknown; + } + } + } + + tagStack.push_back(name); + if (!strcmp(name, DAV_RESPONSE_TAG)) { + currentElementType = DAVResource::Unknown; + currentElementUrl.clear(); + currentElementMD5.clear(); + currentVersionName.clear(); + currentVCC.clear(); + } + } + + void endElement (const char * name) + { + assert(tagStack.back() == name); + tagStack.pop_back(); + + if (!strcmp(name, DAV_RESPONSE_TAG)) { + // finish complete response + currentElementUrl = strutils::strip(currentElementUrl); + + DAVResource* res = NULL; + if (currentElementType == DAVResource::Collection) { + DAVCollection* col = new DAVCollection(currentElementUrl); + res = col; + } else { + res = new DAVResource(currentElementUrl); + } + + res->setVersionName(strutils::strip(currentVersionName)); + res->setVersionControlledConfiguration(currentVCC); + if (rootResource && + strutils::starts_with(currentElementUrl, rootResource->url())) + { + static_cast(rootResource)->addChild(res); + } + + if (!rootResource) { + rootResource = res; + } + } + } + + void data (const char * s, int length) + { + if (tagStack.back() == DAV_HREF_TAG) { + if (tagN(1) == DAV_RESPONSE_TAG) { + currentElementUrl += string(s, length); + } else if (tagN(1) == DAV_VCC_TAG) { + currentVCC += string(s, length); + } + } else if (tagStack.back() == SUBVERSION_MD5_CHECKSUM_TAG) { + currentElementMD5 = string(s, length); + } else if (tagStack.back() == DAV_VERSIONNAME_TAG) { + currentVersionName = string(s, length); + } else if (tagStack.back() == DAV_CONTENT_LENGTH_TAG) { + std::istringstream is(string(s, length)); + is >> currentElementLength; + } + } + + void pi (const char * target, const char * data) {} + + string tagN(const unsigned int n) const + { + size_t sz = tagStack.size(); + if (n >= sz) { + return string(); + } + + return tagStack[sz - (1 + n)]; + } + + bool parserInited; + bool valid; + XML_Parser xmlParser; + DAVResource* rootResource; + + // in-flight data + string_list tagStack; + DAVResource::Type currentElementType; + string currentElementUrl, + currentVersionName, + currentVCC; + int currentElementLength; + string currentElementMD5; +}; + + +//////////////////////////////////////////////////////////////////////// +// Static callback functions for Expat. +//////////////////////////////////////////////////////////////////////// + +#define VISITOR static_cast(userData) + +static void +start_element (void * userData, const char * name, const char ** atts) +{ + VISITOR->startElement(name); +} + +static void +end_element (void * userData, const char * name) +{ + VISITOR->endElement(name); +} + +static void +character_data (void * userData, const char * s, int len) +{ + VISITOR->data(s, len); +} + +static void +processing_instruction (void * userData, + const char * target, + const char * data) +{ + VISITOR->pi(target, data); +} + +#undef VISITOR + +/////////////////////////////////////////////////////////////////////////////// + +DAVMultiStatus::DAVMultiStatus() : +_d(new DAVMultiStatusPrivate) +{ + +} + +DAVMultiStatus::~DAVMultiStatus() +{ + +} + +void DAVMultiStatus::parseXML(const char* data, int size) +{ + if (!_d->parserInited) { + _d->xmlParser = XML_ParserCreateNS(0, ':'); + XML_SetUserData(_d->xmlParser, _d.get()); + XML_SetElementHandler(_d->xmlParser, start_element, end_element); + XML_SetCharacterDataHandler(_d->xmlParser, character_data); + XML_SetProcessingInstructionHandler(_d->xmlParser, processing_instruction); + _d->parserInited = true; + } + + if (!XML_Parse(_d->xmlParser, data, size, false)) { + SG_LOG(SG_IO, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser)) + << " at line:" << XML_GetCurrentLineNumber(_d->xmlParser) + << " column " << XML_GetCurrentColumnNumber(_d->xmlParser)); + + XML_ParserFree(_d->xmlParser); + _d->parserInited = false; + _d->valid = false; + } +} + +void DAVMultiStatus::finishParse() +{ + if (_d->parserInited) { + if (!XML_Parse(_d->xmlParser, NULL, 0, true)) { + SG_LOG(SG_IO, SG_WARN, "DAV parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser)) + << " at line:" << XML_GetCurrentLineNumber(_d->xmlParser) + << " column " << XML_GetCurrentColumnNumber(_d->xmlParser)); + _d->valid = false; + } else { + _d->valid = true; + } + XML_ParserFree(_d->xmlParser); + } + + _d->parserInited = false; +} + +DAVResource* DAVMultiStatus::resource() +{ + return _d->rootResource; +} + +bool DAVMultiStatus::isValid() const +{ + return _d->valid; +} + + diff -Nru simgear-2.10.0/simgear/io/DAVMultiStatus.hxx simgear-3.0.0/simgear/io/DAVMultiStatus.hxx --- simgear-2.10.0/simgear/io/DAVMultiStatus.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/DAVMultiStatus.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,143 @@ +// DAVMultiStatus.hxx -- parser for WebDAV MultiStatus XML data +// +// Copyright (C) 2012 James Turner +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +#ifndef SG_IO_DAVMULTISTATUS_HXX +#define SG_IO_DAVMULTISTATUS_HXX + +#include +#include +#include // for auto_ptr + +namespace simgear +{ + +class DAVCollection; + +class DAVResource +{ +public: + DAVResource(const std::string& url); + virtual ~DAVResource() { } + + typedef enum { + Unknown = 0, + Collection = 1 + } Type; + + const Type type() const + { return _type; } + + const std::string& url() const + { return _url; } + + std::string name() const; + + /** + * SVN servers use this field to expose the head revision + * of the resource, which is useful + */ + const std::string& versionName() const + { return _versionName; } + + void setVersionName(const std::string& aVersion); + + DAVCollection* container() const + { return _container; } + + virtual bool isCollection() const + { return false; } + + void setVersionControlledConfiguration(const std::string& vcc); + const std::string& versionControlledConfiguration() const + { return _vcc; } + + void setMD5(const std::string& md5Hex); + const std::string& md5() const + { return _md5; } +protected: + friend class DAVCollection; + + Type _type; + std::string _url; + std::string _versionName; + std::string _vcc; + std::string _md5; + DAVCollection* _container; +}; + +typedef std::vector DAVResourceList; + +class DAVCollection : public DAVResource +{ +public: + DAVCollection(const std::string& url); + virtual ~DAVCollection(); + + DAVResourceList contents() const; + + void addChild(DAVResource* res); + void removeChild(DAVResource* res); + + DAVCollection* createChildCollection(const std::string& name); + + /** + * find the collection member with the specified URL, or return NULL + * if no such member of this collection exists. + */ + DAVResource* childWithUrl(const std::string& url) const; + + /** + * find the collection member with the specified name, or return NULL + */ + DAVResource* childWithName(const std::string& name) const; + + /** + * wrapper around URL manipulation + */ + std::string urlForChildWithName(const std::string& name) const; + + virtual bool isCollection() const + { return true; } +private: + DAVResourceList _contents; +}; + +class DAVMultiStatus +{ +public: + DAVMultiStatus(); + ~DAVMultiStatus(); + + // incremental XML parsing + void parseXML(const char* data, int size); + + void finishParse(); + + bool isValid() const; + + DAVResource* resource(); + + class DAVMultiStatusPrivate; +private: + std::auto_ptr _d; +}; + +} // of namespace simgear + +#endif // of SG_IO_DAVMULTISTATUS_HXX diff -Nru simgear-2.10.0/simgear/io/HTTPClient.cxx simgear-3.0.0/simgear/io/HTTPClient.cxx --- simgear-2.10.0/simgear/io/HTTPClient.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/io/HTTPClient.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -1,22 +1,47 @@ +/** + * \file HTTPClient.cxx - simple HTTP client engine for SimHear + */ + +// Written by James Turner +// +// Copyright (C) 2013 James Turner +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + #include "HTTPClient.hxx" +#include "HTTPFileRequest.hxx" #include #include +#include // rand() #include -#include #include +#include +#include #include #include -#include - #include -#include +#include #include #include #include #include +#include #if defined( HAVE_VERSION_H ) && HAVE_VERSION_H #include "version.h" @@ -26,10 +51,6 @@ # endif #endif -using std::string; -using std::stringstream; -using std::vector; - namespace simgear { @@ -39,19 +60,31 @@ extern const int DEFAULT_HTTP_PORT = 80; const char* CONTENT_TYPE_URL_ENCODED = "application/x-www-form-urlencoded"; const unsigned int MAX_INFLIGHT_REQUESTS = 32; -const int ZLIB_DECOMPRESS_BUFFER_SIZE = 32 * 1024; -const int ZLIB_INFLATE_WINDOW_BITS = -MAX_WBITS; - -// see http://www.ietf.org/rfc/rfc1952.txt for these values and -// detailed description of the logic -const int GZIP_HEADER_ID1 = 31; -const int GZIP_HEADER_ID2 = 139; -const int GZIP_HEADER_METHOD_DEFLATE = 8; -const int GZIP_HEADER_SIZE = 10; -const int GZIP_HEADER_FEXTRA = 1 << 2; -const int GZIP_HEADER_FNAME = 1 << 3; -const int GZIP_HEADER_COMMENT = 1 << 4; -const int GZIP_HEADER_CRC = 1 << 1; + +class Connection; +typedef std::multimap ConnectionDict; +typedef std::list RequestList; + +class Client::ClientPrivate +{ +public: + std::string userAgent; + std::string proxy; + int proxyPort; + std::string proxyAuth; + NetChannelPoller poller; + unsigned int maxConnections; + + RequestList pendingRequests; + +// connections by host (potentially more than one) + ConnectionDict connections; + + SGTimeStamp timeTransferSample; + unsigned int bytesTransferred; + unsigned int lastTransferRate; + uint64_t totalBytesDownloaded; +}; class Connection : public NetChat { @@ -59,26 +92,28 @@ Connection(Client* pr) : client(pr), state(STATE_CLOSED), - port(DEFAULT_HTTP_PORT), - zlibInflateBuffer(NULL), - zlibInflateBufferSize(0), - zlibOutputBuffer(NULL) + port(DEFAULT_HTTP_PORT) { - } virtual ~Connection() { - if (zlibInflateBuffer) { - free(zlibInflateBuffer); - } - - if (zlibOutputBuffer) { - free(zlibOutputBuffer); - } + } + + virtual void handleBufferRead (NetBuffer& buffer) + { + if( !activeRequest || !activeRequest->isComplete() ) + return NetChat::handleBufferRead(buffer); + + // Request should be aborted (signaled by setting its state to complete). + + // force the state to GETTING_BODY, to simplify logic in + // responseComplete and handleClose + state = STATE_GETTING_BODY; + responseComplete(); } - void setServer(const string& h, short p) + void setServer(const std::string& h, short p) { host = h; port = p; @@ -109,6 +144,7 @@ SG_LOG(SG_IO, SG_INFO, "HTTP socket error"); activeRequest->setFailure(error, "socket error"); activeRequest = NULL; + _contentDecoder.reset(); } state = STATE_SOCKET_ERROR; @@ -117,13 +153,28 @@ virtual void handleClose() { NetChat::handleClose(); - - if ((state == STATE_GETTING_BODY) && activeRequest) { + + // closing of the connection from the server side when getting the body, + bool canCloseState = (state == STATE_GETTING_BODY); + if (canCloseState && activeRequest) { // force state here, so responseComplete can avoid closing the // socket again state = STATE_CLOSED; responseComplete(); } else { + if (activeRequest) { + activeRequest->setFailure(500, "server closed connection"); + // remove the failed request from sentRequests, so it does + // not get restored + RequestList::iterator it = std::find(sentRequests.begin(), + sentRequests.end(), activeRequest); + if (it != sentRequests.end()) { + sentRequests.erase(it); + } + activeRequest = NULL; + _contentDecoder.reset(); + } + state = STATE_CLOSED; } @@ -138,18 +189,37 @@ sentRequests.clear(); } + void handleTimeout() + { + NetChat::handleError(ETIMEDOUT); + if (activeRequest) { + SG_LOG(SG_IO, SG_DEBUG, "HTTP socket timeout"); + activeRequest->setFailure(ETIMEDOUT, "socket timeout"); + activeRequest = NULL; + _contentDecoder.reset(); + } + + state = STATE_SOCKET_ERROR; + } + void queueRequest(const Request_ptr& r) { - queuedRequests.push_back(r); - tryStartNextRequest(); + queuedRequests.push_back(r); + tryStartNextRequest(); } void beginResponse() { - assert(!sentRequests.empty()); - - activeRequest = sentRequests.front(); - activeRequest->responseStart(buffer); + assert(!sentRequests.empty()); + assert(state == STATE_WAITING_FOR_RESPONSE); + + activeRequest = sentRequests.front(); + try { + activeRequest->responseStart(buffer); + } catch (sg_exception& e) { + handleError(EIO); + } + state = STATE_GETTING_HEADERS; buffer.clear(); if (activeRequest->responseCode() == 204) { @@ -162,11 +232,15 @@ bodyTransferSize = -1; chunkedTransfer = false; - contentGZip = contentDeflate = false; + _contentDecoder.reset(); } void tryStartNextRequest() { + while( !queuedRequests.empty() + && queuedRequests.front()->isComplete() ) + queuedRequests.pop_front(); + if (queuedRequests.empty()) { idleTime.stamp(); return; @@ -186,28 +260,29 @@ } Request_ptr r = queuedRequests.front(); - requestBodyBytesToSend = r->requestBodyLength(); - - stringstream headerData; - string path = r->path(); + r->requestStart(); + + std::stringstream headerData; + std::string path = r->path(); assert(!path.empty()); - string query = r->query(); - string bodyData; + std::string query = r->query(); + std::string bodyData; if (!client->proxyHost().empty()) { path = r->scheme() + "://" + r->host() + r->path(); } - if (r->requestBodyType() == CONTENT_TYPE_URL_ENCODED) { + if (r->bodyType() == CONTENT_TYPE_URL_ENCODED) { headerData << r->method() << " " << path << " HTTP/1.1\r\n"; bodyData = query.substr(1); // URL-encode, drop the leading '?' headerData << "Content-Type:" << CONTENT_TYPE_URL_ENCODED << "\r\n"; headerData << "Content-Length:" << bodyData.size() << "\r\n"; } else { headerData << r->method() << " " << path << query << " HTTP/1.1\r\n"; - if (requestBodyBytesToSend >= 0) { - headerData << "Content-Length:" << requestBodyBytesToSend << "\r\n"; - headerData << "Content-Type:" << r->requestBodyType() << "\r\n"; + if( r->hasBodyData() ) + { + headerData << "Content-Length:" << r->bodyLength() << "\r\n"; + headerData << "Content-Type:" << r->bodyType() << "\r\n"; } } @@ -218,8 +293,8 @@ headerData << "Proxy-Authorization: " << client->proxyAuth() << "\r\n"; } - BOOST_FOREACH(string h, r->requestHeaders()) { - headerData << h << ": " << r->header(h) << "\r\n"; + BOOST_FOREACH(const StringMap::value_type& h, r->requestHeaders()) { + headerData << h.first << ": " << h.second << "\r\n"; } headerData << "\r\n"; // final CRLF to terminate the headers @@ -229,163 +304,67 @@ bool ok = push(headerData.str().c_str()); if (!ok) { + SG_LOG(SG_IO, SG_WARN, "HTTPClient: over-stuffed the socket"); // we've over-stuffed the socket, give up for now, let things // drain down before trying to start any more requests. return; } - - while (requestBodyBytesToSend > 0) { - char buf[4096]; - int len = 4096; - r->getBodyData(buf, len); - if (len > 0) { - requestBodyBytesToSend -= len; - if (!bufferSend(buf, len)) { - SG_LOG(SG_IO, SG_WARN, "overflow the HTTP::Connection output buffer"); - state = STATE_SOCKET_ERROR; - return; + + if( r->hasBodyData() ) + for(size_t body_bytes_sent = 0; body_bytes_sent < r->bodyLength();) + { + char buf[4096]; + size_t len = r->getBodyData(buf, body_bytes_sent, 4096); + if( len ) + { + if( !bufferSend(buf, len) ) + { + SG_LOG(SG_IO, + SG_WARN, + "overflow the HTTP::Connection output buffer"); + state = STATE_SOCKET_ERROR; + return; + } + body_bytes_sent += len; + } + else + { + SG_LOG(SG_IO, + SG_WARN, + "HTTP asynchronous request body generation is unsupported"); + break; } - } else { - SG_LOG(SG_IO, SG_WARN, "asynchronous request body generation is unsupported"); - break; } - } - //std::cout << "did send request:" << r->url() << std::endl; - // successfully sent, remove from queue, and maybe send the next + // SG_LOG(SG_IO, SG_INFO, "did start request:" << r->url() << + // "\n\t @ " << reinterpret_cast(r.ptr()) << + // "\n\t on connection " << this); + // successfully sent, remove from queue, and maybe send the next queuedRequests.pop_front(); sentRequests.push_back(r); - - // pipelining, let's maybe send the next request right away + state = STATE_WAITING_FOR_RESPONSE; + + // pipelining, let's maybe send the next request right away tryStartNextRequest(); } virtual void collectIncomingData(const char* s, int n) { idleTime.stamp(); - if ((state == STATE_GETTING_BODY) || (state == STATE_GETTING_CHUNKED_BYTES)) { - if (contentGZip || contentDeflate) { - expandCompressedData(s, n); - } else { - activeRequest->processBodyBytes(s, n); - } - } else { - buffer += string(s, n); - } - } + client->receivedBytes(static_cast(n)); - - void expandCompressedData(const char* s, int n) - { - int reqSize = n + zlib.avail_in; - if (reqSize > zlibInflateBufferSize) { - // reallocate - unsigned char* newBuf = (unsigned char*) malloc(reqSize); - memcpy(newBuf, zlib.next_in, zlib.avail_in); - memcpy(newBuf + zlib.avail_in, s, n); - free(zlibInflateBuffer); - zlibInflateBuffer = newBuf; - zlibInflateBufferSize = reqSize; - } else { - // important to use memmove here, since it's very likely - // the source and destination ranges overlap - memmove(zlibInflateBuffer, zlib.next_in, zlib.avail_in); - memcpy(zlibInflateBuffer + zlib.avail_in, s, n); - } - - zlib.next_in = (unsigned char*) zlibInflateBuffer; - zlib.avail_in = reqSize; - zlib.next_out = zlibOutputBuffer; - zlib.avail_out = ZLIB_DECOMPRESS_BUFFER_SIZE; - - if (contentGZip) { - // we clear this down to contentDeflate once the GZip header has been seen - if (reqSize < GZIP_HEADER_SIZE) { - return; // need more header bytes - } - - if ((zlibInflateBuffer[0] != GZIP_HEADER_ID1) || - (zlibInflateBuffer[1] != GZIP_HEADER_ID2) || - (zlibInflateBuffer[2] != GZIP_HEADER_METHOD_DEFLATE)) - { - return; // invalid GZip header - } - - char flags = zlibInflateBuffer[3]; - int gzipHeaderSize = GZIP_HEADER_SIZE; - if (flags & GZIP_HEADER_FEXTRA) { - gzipHeaderSize += 2; - if (reqSize < gzipHeaderSize) { - return; // need more header bytes - } - - unsigned short extraHeaderBytes = *(reinterpret_cast(zlibInflateBuffer + GZIP_HEADER_FEXTRA)); - if ( sgIsBigEndian() ) { - sgEndianSwap( &extraHeaderBytes ); - } - - gzipHeaderSize += extraHeaderBytes; - if (reqSize < gzipHeaderSize) { - return; // need more header bytes - } - } - - if (flags & GZIP_HEADER_FNAME) { - gzipHeaderSize++; - while (gzipHeaderSize <= reqSize) { - if (zlibInflateBuffer[gzipHeaderSize-1] == 0) { - break; // found terminating NULL character - } - } - } - - if (flags & GZIP_HEADER_COMMENT) { - gzipHeaderSize++; - while (gzipHeaderSize <= reqSize) { - if (zlibInflateBuffer[gzipHeaderSize-1] == 0) { - break; // found terminating NULL character - } - } - } - - if (flags & GZIP_HEADER_CRC) { - gzipHeaderSize += 2; - } - - if (reqSize < gzipHeaderSize) { - return; // need more header bytes - } - - zlib.next_in += gzipHeaderSize; - zlib.avail_in = reqSize - gzipHeaderSize; - // now we've processed the GZip header, can decode as deflate - contentGZip = false; - contentDeflate = true; - } - - int writtenSize = 0; - do { - int result = inflate(&zlib, Z_NO_FLUSH); - if (result == Z_OK || result == Z_STREAM_END) { - - } else { - SG_LOG(SG_IO, SG_WARN, "got Zlib error:" << result); - return; - } - - writtenSize = ZLIB_DECOMPRESS_BUFFER_SIZE - zlib.avail_out; - } while ((writtenSize == 0) && (zlib.avail_in > 0)); - - if (writtenSize > 0) { - activeRequest->processBodyBytes((const char*) zlibOutputBuffer, writtenSize); - } + if( (state == STATE_GETTING_BODY) + || (state == STATE_GETTING_CHUNKED_BYTES) ) + _contentDecoder.receivedBytes(s, n); + else + buffer.append(s, n); } - + virtual void foundTerminator(void) { idleTime.stamp(); switch (state) { - case STATE_IDLE: + case STATE_WAITING_FOR_RESPONSE: beginResponse(); break; @@ -405,6 +384,7 @@ case STATE_GETTING_CHUNKED_BYTES: setTerminator("\r\n"); state = STATE_GETTING_CHUNKED; + buffer.clear(); break; @@ -413,6 +393,9 @@ buffer.clear(); break; + case STATE_IDLE: + SG_LOG(SG_IO, SG_WARN, "HTTP got data in IDLE state, bad server?"); + default: break; } @@ -424,6 +407,7 @@ return false; } + assert(sentRequests.empty()); return idleTime.elapsedMSec() > 1000 * 10; // ten seconds } @@ -445,6 +429,11 @@ { return !queuedRequests.empty() && (sentRequests.size() < MAX_INFLIGHT_REQUESTS); } + + bool isActive() const + { + return !queuedRequests.empty() || !sentRequests.empty(); + } private: bool connectToHost() { @@ -465,37 +454,9 @@ void processHeader() { - string h = strutils::simplify(buffer); + std::string h = strutils::simplify(buffer); if (h.empty()) { // blank line terminates headers headersComplete(); - - if (contentGZip || contentDeflate) { - memset(&zlib, 0, sizeof(z_stream)); - if (!zlibOutputBuffer) { - zlibOutputBuffer = (unsigned char*) malloc(ZLIB_DECOMPRESS_BUFFER_SIZE); - } - - // NULLs means we'll get default alloc+free methods - // which is absolutely fine - zlib.avail_out = ZLIB_DECOMPRESS_BUFFER_SIZE; - zlib.next_out = zlibOutputBuffer; - if (inflateInit2(&zlib, ZLIB_INFLATE_WINDOW_BITS) != Z_OK) { - SG_LOG(SG_IO, SG_WARN, "inflateInit2 failed"); - } - } - - if (chunkedTransfer) { - state = STATE_GETTING_CHUNKED; - } else if (noMessageBody || (bodyTransferSize == 0)) { - // force the state to GETTING_BODY, to simplify logic in - // responseComplete and handleClose - state = STATE_GETTING_BODY; - responseComplete(); - } else { - setByteCount(bodyTransferSize); // may be -1, that's fine - state = STATE_GETTING_BODY; - } - return; } @@ -505,9 +466,9 @@ return; } - string key = strutils::simplify(buffer.substr(0, colonPos)); - string lkey = boost::to_lower_copy(key); - string value = strutils::strip(buffer.substr(colonPos + 1)); + std::string key = strutils::simplify(buffer.substr(0, colonPos)); + std::string lkey = boost::to_lower_copy(key); + std::string value = strutils::strip(buffer.substr(colonPos + 1)); // only consider these if getting headers (as opposed to trailers // of a chunked transfer) @@ -524,20 +485,14 @@ } else if (lkey == "transfer-encoding") { processTransferEncoding(value); } else if (lkey == "content-encoding") { - if (value == "gzip") { - contentGZip = true; - } else if (value == "deflate") { - contentDeflate = true; - } else if (value != "identity") { - SG_LOG(SG_IO, SG_WARN, "unsupported content encoding:" << value); - } + _contentDecoder.setEncoding(value); } } activeRequest->responseHeader(lkey, value); } - void processTransferEncoding(const string& te) + void processTransferEncoding(const std::string& te) { if (te == "chunked") { chunkedTransfer = true; @@ -553,7 +508,7 @@ // blank line after chunk data return; } - + int chunkSize = 0; int semiPos = buffer.find(';'); if (semiPos >= 0) { @@ -588,17 +543,25 @@ void headersComplete() { activeRequest->responseHeadersComplete(); + _contentDecoder.initWithRequest(activeRequest); + + if (chunkedTransfer) { + state = STATE_GETTING_CHUNKED; + } else if (noMessageBody || (bodyTransferSize == 0)) { + // force the state to GETTING_BODY, to simplify logic in + // responseComplete and handleClose + state = STATE_GETTING_BODY; + responseComplete(); + } else { + setByteCount(bodyTransferSize); // may be -1, that's fine + state = STATE_GETTING_BODY; + } } void responseComplete() { - //std::cout << "responseComplete:" << activeRequest->url() << std::endl; - activeRequest->responseComplete(); - client->requestFinished(this); - - if (contentDeflate) { - inflateEnd(&zlib); - } + Request_ptr completedRequest = activeRequest; + _contentDecoder.finish(); assert(sentRequests.front() == activeRequest); sentRequests.pop_front(); @@ -609,21 +572,29 @@ if (doClose) { // this will bring us into handleClose() above, which updates // state to STATE_CLOSED - close(); + close(); // if we have additional requests waiting, try to start them now - tryStartNextRequest(); - } + tryStartNextRequest(); + } } - if (state != STATE_CLOSED) { - state = STATE_IDLE; - } - setTerminator("\r\n"); + if (state != STATE_CLOSED) { + state = sentRequests.empty() ? STATE_IDLE : STATE_WAITING_FOR_RESPONSE; + } + + // notify request after we change state, so this connection is idle + // if completion triggers other requests (which is likely) + // SG_LOG(SG_IO, SG_INFO, "*** responseComplete:" << activeRequest->url()); + completedRequest->responseComplete(); + client->requestFinished(this); + + setTerminator("\r\n"); } enum ConnectionState { STATE_IDLE = 0, + STATE_WAITING_FOR_RESPONSE, STATE_GETTING_HEADERS, STATE_GETTING_BODY, STATE_GETTING_CHUNKED, @@ -636,74 +607,187 @@ Client* client; Request_ptr activeRequest; ConnectionState state; - string host; + std::string host; short port; std::string buffer; int bodyTransferSize; SGTimeStamp idleTime; bool chunkedTransfer; bool noMessageBody; - int requestBodyBytesToSend; - - z_stream zlib; - unsigned char* zlibInflateBuffer; - int zlibInflateBufferSize; - unsigned char* zlibOutputBuffer; - bool contentGZip, contentDeflate; - - std::list queuedRequests; - std::list sentRequests; + + RequestList queuedRequests; + RequestList sentRequests; + + ContentDecoder _contentDecoder; }; -Client::Client() +Client::Client() : + d(new ClientPrivate) { + d->proxyPort = 0; + d->maxConnections = 4; + d->bytesTransferred = 0; + d->lastTransferRate = 0; + d->timeTransferSample.stamp(); + d->totalBytesDownloaded = 0; + setUserAgent("SimGear-" SG_STRINGIZE(SIMGEAR_VERSION)); } +Client::~Client() +{ +} + +void Client::setMaxConnections(unsigned int maxCon) +{ + if (maxCon < 1) { + throw sg_range_exception("illegal HTTP::Client::setMaxConnections value"); + } + + d->maxConnections = maxCon; +} + void Client::update(int waitTimeout) { - NetChannel::poll(waitTimeout); - - ConnectionDict::iterator it = _connections.begin(); - for (; it != _connections.end(); ) { - if (it->second->hasIdleTimeout() || it->second->hasError() || - it->second->hasErrorTimeout()) + if (!d->poller.hasChannels() && (waitTimeout > 0)) { + SGTimeStamp::sleepForMSec(waitTimeout); + } else { + d->poller.poll(waitTimeout); + } + + bool waitingRequests = !d->pendingRequests.empty(); + ConnectionDict::iterator it = d->connections.begin(); + for (; it != d->connections.end(); ) { + Connection* con = it->second; + if (con->hasIdleTimeout() || + con->hasError() || + con->hasErrorTimeout() || + (!con->isActive() && waitingRequests)) { + if (con->hasErrorTimeout()) { + // tell the connection we're timing it out + con->handleTimeout(); + } + // connection has been idle for a while, clean it up - // (or has an error condition, again clean it up) + // (or if we have requests waiting for a different host, + // or an error condition ConnectionDict::iterator del = it++; delete del->second; - _connections.erase(del); + d->connections.erase(del); } else { if (it->second->shouldStartNext()) { it->second->tryStartNextRequest(); } - ++it; } - } // of connecion iteration + } // of connection iteration + + if (waitingRequests && (d->connections.size() < d->maxConnections)) { + RequestList waiting(d->pendingRequests); + d->pendingRequests.clear(); + + // re-submit all waiting requests in order; this takes care of + // finding multiple pending items targetted to the same (new) + // connection + BOOST_FOREACH(Request_ptr req, waiting) { + makeRequest(req); + } + } } void Client::makeRequest(const Request_ptr& r) { - string host = r->host(); + if( r->isComplete() ) + return; + + if( r->url().find("://") == std::string::npos ) { + r->setFailure(EINVAL, "malformed URL"); + return; + } + + if( r->url().find("http://") != 0 ) { + r->setFailure(EINVAL, "only HTTP protocol is supported"); + return; + } + + std::string host = r->host(); int port = r->port(); - if (!_proxy.empty()) { - host = _proxy; - port = _proxyPort; + if (!d->proxy.empty()) { + host = d->proxy; + port = d->proxyPort; } - stringstream ss; + Connection* con = NULL; + std::stringstream ss; ss << host << "-" << port; - string connectionId = ss.str(); + std::string connectionId = ss.str(); + bool havePending = !d->pendingRequests.empty(); + bool atConnectionsLimit = d->connections.size() >= d->maxConnections; + ConnectionDict::iterator consEnd = d->connections.end(); + + // assign request to an existing Connection. + // various options exist here, examined in order + ConnectionDict::iterator it = d->connections.find(connectionId); + if (atConnectionsLimit && (it == consEnd)) { + // maximum number of connections active, queue this request + // when a connection goes inactive, we'll start this one + d->pendingRequests.push_back(r); + return; + } - if (_connections.find(connectionId) == _connections.end()) { - Connection* con = new Connection(this); + // scan for an idle Connection to the same host (likely if we're + // retrieving multiple resources from the same host in quick succession) + // if we have pending requests (waiting for a free Connection), then + // force new requests on this id to always use the first Connection + // (instead of the random selection below). This ensures that when + // there's pressure on the number of connections to keep alive, one + // host can't DoS every other. + int count = 0; + for (; (it != consEnd) && (it->first == connectionId); ++it, ++count) { + if (havePending || !it->second->isActive()) { + con = it->second; + break; + } + } + + if (!con && atConnectionsLimit) { + // all current connections are busy (active), and we don't + // have free connections to allocate, so let's assign to + // an existing one randomly. Ideally we'd used whichever one will + // complete first but we don't have that info. + int index = rand() % count; + for (it = d->connections.find(connectionId); index > 0; --index) { ; } + con = it->second; + } + + // allocate a new connection object + if (!con) { + con = new Connection(this); con->setServer(host, port); - _connections[connectionId] = con; + d->poller.addChannel(con); + d->connections.insert(d->connections.end(), + ConnectionDict::value_type(connectionId, con)); } - _connections[connectionId]->queueRequest(r); + con->queueRequest(r); +} + +//------------------------------------------------------------------------------ +FileRequestRef Client::save( const std::string& url, + const std::string& filename ) +{ + FileRequestRef req = new FileRequest(url, filename); + makeRequest(req); + return req; +} + +//------------------------------------------------------------------------------ +MemoryRequestRef Client::load(const std::string& url) +{ + MemoryRequestRef req = new MemoryRequest(url); + makeRequest(req); + return req; } void Client::requestFinished(Connection* con) @@ -711,16 +795,80 @@ } -void Client::setUserAgent(const string& ua) +void Client::setUserAgent(const std::string& ua) +{ + d->userAgent = ua; +} + +const std::string& Client::userAgent() const +{ + return d->userAgent; +} + +const std::string& Client::proxyHost() const +{ + return d->proxy; +} + +const std::string& Client::proxyAuth() const +{ + return d->proxyAuth; +} + +void Client::setProxy( const std::string& proxy, + int port, + const std::string& auth ) +{ + d->proxy = proxy; + d->proxyPort = port; + d->proxyAuth = auth; +} + +bool Client::hasActiveRequests() const +{ + ConnectionDict::const_iterator it = d->connections.begin(); + for (; it != d->connections.end(); ++it) { + if (it->second->isActive()) return true; + } + + return false; +} + +void Client::receivedBytes(unsigned int count) +{ + d->bytesTransferred += count; + d->totalBytesDownloaded += count; +} + +unsigned int Client::transferRateBytesPerSec() const { - _userAgent = ua; + unsigned int e = d->timeTransferSample.elapsedMSec(); + if (e > 400) { + // too long a window, ignore + d->timeTransferSample.stamp(); + d->bytesTransferred = 0; + d->lastTransferRate = 0; + return 0; + } + + if (e < 100) { // avoid really narrow windows + return d->lastTransferRate; + } + + unsigned int ratio = (d->bytesTransferred * 1000) / e; + // run a low-pass filter + unsigned int smoothed = ((400 - e) * d->lastTransferRate) + (e * ratio); + smoothed /= 400; + + d->timeTransferSample.stamp(); + d->bytesTransferred = 0; + d->lastTransferRate = smoothed; + return smoothed; } -void Client::setProxy(const string& proxy, int port, const string& auth) +uint64_t Client::totalBytesDownloaded() const { - _proxy = proxy; - _proxyPort = port; - _proxyAuth = auth; + return d->totalBytesDownloaded; } } // of namespace HTTP diff -Nru simgear-2.10.0/simgear/io/HTTPClient.hxx simgear-3.0.0/simgear/io/HTTPClient.hxx --- simgear-2.10.0/simgear/io/HTTPClient.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/io/HTTPClient.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -1,9 +1,34 @@ +/** + * \file HTTPClient.hxx - simple HTTP client engine for SimHear + */ + +// Written by James Turner +// +// Copyright (C) 2013 James Turner +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + #ifndef SG_HTTP_CLIENT_HXX #define SG_HTTP_CLIENT_HXX -#include +#include // for std::auto_ptr +#include // for uint_64t -#include +#include +#include namespace simgear { @@ -11,42 +36,78 @@ namespace HTTP { +// forward decls class Connection; - + class Client { public: Client(); + ~Client(); void update(int waitTimeout = 0); void makeRequest(const Request_ptr& r); - + + /** + * Download a resource and save it to a file. + * + * @param url The resource to download + * @param filename Path to the target file + * @param data Data for POST request + */ + FileRequestRef save( const std::string& url, + const std::string& filename ); + + /** + * Request a resource and keep it in memory. + * + * @param url The resource to download + */ + MemoryRequestRef load(const std::string& url); + void setUserAgent(const std::string& ua); void setProxy(const std::string& proxy, int port, const std::string& auth = ""); - const std::string& userAgent() const - { return _userAgent; } + /** + * Specify the maximum permitted simultaneous connections + * (default value is 1) + */ + void setMaxConnections(unsigned int maxCons); + + const std::string& userAgent() const; - const std::string& proxyHost() const - { return _proxy; } + const std::string& proxyHost() const; - const std::string& proxyAuth() const - { return _proxyAuth; } + const std::string& proxyAuth() const; + + /** + * predicate, check if at least one connection is active, with at + * least one request active or queued. + */ + bool hasActiveRequests() const; + + /** + * crude tracking of bytes-per-second transferred over the socket. + * suitable for user feedback and rough profiling, nothing more. + */ + unsigned int transferRateBytesPerSec() const; + + /** + * total bytes downloaded by this HTTP client, for bandwidth usage + * monitoring + */ + uint64_t totalBytesDownloaded() const; private: void requestFinished(Connection* con); + void receivedBytes(unsigned int count); + friend class Connection; friend class Request; - std::string _userAgent; - std::string _proxy; - int _proxyPort; - std::string _proxyAuth; - -// connections by host - typedef std::map ConnectionDict; - ConnectionDict _connections; + class ClientPrivate; + std::auto_ptr d; }; } // of namespace HTTP diff -Nru simgear-2.10.0/simgear/io/HTTPContentDecode.cxx simgear-3.0.0/simgear/io/HTTPContentDecode.cxx --- simgear-2.10.0/simgear/io/HTTPContentDecode.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/HTTPContentDecode.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,269 @@ +// Written by James Turner +// +// Copyright (C) 2013 James Turner +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include "HTTPContentDecode.hxx" + +#include +#include // rand() +#include // for memset, memcpy + +#include +#include +#include // for sgEndian stuff + +namespace simgear +{ + +namespace HTTP +{ + + const int ZLIB_DECOMPRESS_BUFFER_SIZE = 32 * 1024; + const int ZLIB_INFLATE_WINDOW_BITS = -MAX_WBITS; + + // see http://www.ietf.org/rfc/rfc1952.txt for these values and + // detailed description of the logic + const int GZIP_HEADER_ID1 = 31; + const int GZIP_HEADER_ID2 = 139; + const int GZIP_HEADER_METHOD_DEFLATE = 8; + const unsigned int GZIP_HEADER_SIZE = 10; + const int GZIP_HEADER_FEXTRA = 1 << 2; + const int GZIP_HEADER_FNAME = 1 << 3; + const int GZIP_HEADER_COMMENT = 1 << 4; + const int GZIP_HEADER_CRC = 1 << 1; + +ContentDecoder::ContentDecoder() : + _output(NULL), + _zlib(NULL), + _input(NULL), + _inputAllocated(0), + _inputSize(0) +{ +} + +ContentDecoder::~ContentDecoder() +{ + free(_output); + free(_input); + free(_zlib); +} + +void ContentDecoder::setEncoding(const std::string& encoding) +{ + if (encoding == "gzip") { + _contentDeflate = true; + _needGZipHeader = true; + } else if (encoding == "deflate") { + _contentDeflate = true; + _needGZipHeader = false; + } else if (encoding != "identity") { + SG_LOG(SG_IO, SG_WARN, "unsupported content encoding:" << encoding); + } +} + +void ContentDecoder::reset() +{ + _request = NULL; + _contentDeflate = false; + _needGZipHeader = false; + _inputSize = 0; +} + +void ContentDecoder::initWithRequest(Request_ptr req) +{ + _request = req; + if (!_contentDeflate) { + return; + } + + if (!_zlib) { + _zlib = (z_stream*) malloc(sizeof(z_stream)); + } + + memset(_zlib, 0, sizeof(z_stream)); + if (!_output) { + _output = (unsigned char*) malloc(ZLIB_DECOMPRESS_BUFFER_SIZE); + } + + _inputSize = 0; + // NULLs means we'll get default alloc+free methods + // which is absolutely fine + _zlib->avail_out = ZLIB_DECOMPRESS_BUFFER_SIZE; + _zlib->next_out = _output; + if (inflateInit2(_zlib, ZLIB_INFLATE_WINDOW_BITS) != Z_OK) { + SG_LOG(SG_IO, SG_WARN, "inflateInit2 failed"); + } +} + +void ContentDecoder::finish() +{ + if (_contentDeflate) { + runDecoder(); + inflateEnd(_zlib); + } +} + +void ContentDecoder::receivedBytes(const char* n, size_t s) +{ + if (!_contentDeflate) { + _request->processBodyBytes(n, s); + return; + } + +// allocate more space if needed (this will only happen rarely once the +// buffer has hit something proportionate to the server's compression +// window size) + size_t requiredSize = _inputSize + s; + if (requiredSize > _inputAllocated) { + reallocateInputBuffer(requiredSize); + } + +// copy newly recieved bytes into the buffer + memcpy(_input + _inputSize, n, s); + _inputSize += s; + + if (_needGZipHeader && !consumeGZipHeader()) { + // still waiting on the full GZIP header, so done + return; + } + + runDecoder(); +} + +void ContentDecoder::consumeBytes(size_t consumed) +{ + assert(_inputSize >= consumed); +// move existing (consumed) bytes down + if (consumed > 0) { + size_t newSize = _inputSize - consumed; + memmove(_input, _input + consumed, newSize); + _inputSize = newSize; + } +} + +void ContentDecoder::reallocateInputBuffer(size_t newSize) +{ + _input = (unsigned char*) realloc(_input, newSize); + _inputAllocated = newSize; +} + +void ContentDecoder::runDecoder() +{ + _zlib->next_in = (unsigned char*) _input; + _zlib->avail_in = _inputSize; + int writtenSize; + + // loop, running zlib() inflate and sending output bytes to + // our request body handler. Keep calling inflate until no bytes are + // written, and ZLIB has consumed all available input + do { + _zlib->next_out = _output; + _zlib->avail_out = ZLIB_DECOMPRESS_BUFFER_SIZE; + int result = inflate(_zlib, Z_NO_FLUSH); + if (result == Z_OK || result == Z_STREAM_END) { + // nothing to do + } else if (result == Z_BUF_ERROR) { + // transient error, fall through + } else { + // _error = result; + return; + } + + writtenSize = ZLIB_DECOMPRESS_BUFFER_SIZE - _zlib->avail_out; + if (writtenSize > 0) { + _request->processBodyBytes((char*) _output, writtenSize); + } + + if (result == Z_STREAM_END) { + break; + } + } while ((_zlib->avail_in > 0) || (writtenSize > 0)); + + // update input buffers based on what we consumed + consumeBytes(_inputSize - _zlib->avail_in); +} + +bool ContentDecoder::consumeGZipHeader() +{ + size_t avail = _inputSize; + if (avail < GZIP_HEADER_SIZE) { + return false; // need more header bytes + } + + if ((_input[0] != GZIP_HEADER_ID1) || + (_input[1] != GZIP_HEADER_ID2) || + (_input[2] != GZIP_HEADER_METHOD_DEFLATE)) + { + return false; // invalid GZip header + } + + char flags = _input[3]; + unsigned int gzipHeaderSize = GZIP_HEADER_SIZE; + if (flags & GZIP_HEADER_FEXTRA) { + gzipHeaderSize += 2; + if (avail < gzipHeaderSize) { + return false; // need more header bytes + } + + unsigned short extraHeaderBytes = *(reinterpret_cast(_input + GZIP_HEADER_FEXTRA)); + if ( sgIsBigEndian() ) { + sgEndianSwap( &extraHeaderBytes ); + } + + gzipHeaderSize += extraHeaderBytes; + if (avail < gzipHeaderSize) { + return false; // need more header bytes + } + } + +#if 0 + if (flags & GZIP_HEADER_FNAME) { + gzipHeaderSize++; + while (gzipHeaderSize <= avail) { + if (_input[gzipHeaderSize-1] == 0) { + break; // found terminating NULL character + } + } + } + + if (flags & GZIP_HEADER_COMMENT) { + gzipHeaderSize++; + while (gzipHeaderSize <= avail) { + if (_input[gzipHeaderSize-1] == 0) { + break; // found terminating NULL character + } + } + } +#endif + + if (flags & GZIP_HEADER_CRC) { + gzipHeaderSize += 2; + } + + if (avail < gzipHeaderSize) { + return false; // need more header bytes + } + + consumeBytes(gzipHeaderSize); + _needGZipHeader = false; + return true; +} + +} // of namespace HTTP + +} // of namespace simgear diff -Nru simgear-2.10.0/simgear/io/HTTPContentDecode.hxx simgear-3.0.0/simgear/io/HTTPContentDecode.hxx --- simgear-2.10.0/simgear/io/HTTPContentDecode.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/HTTPContentDecode.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,72 @@ +// Written by James Turner +// +// Copyright (C) 2013 James Turner +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef SG_HTTP_CONTENT_DECODER_HXX +#define SG_HTTP_CONTENT_DECODER_HXX + +#include + +#include + +#include + + +namespace simgear +{ + +namespace HTTP +{ + +class ContentDecoder +{ +public: + ContentDecoder(); + ~ContentDecoder(); + + void reset(); + + void initWithRequest(Request_ptr req); + + void finish(); + + void setEncoding(const std::string& encoding); + + void receivedBytes(const char* n, size_t s); + +private: + bool consumeGZipHeader(); + void runDecoder(); + + void consumeBytes(size_t consumed); + void reallocateInputBuffer(size_t newSize); + + Request_ptr _request; + unsigned char* _output; + + z_stream* _zlib; + unsigned char* _input; + size_t _inputAllocated, _inputSize; + bool _contentDeflate, _needGZipHeader; +}; + +} // of namespace HTTP + +} // of namespace simgear + +#endif // of SG_HTTP_CONTENT_DECODER_HXX diff -Nru simgear-2.10.0/simgear/io/HTTPFileRequest.cxx simgear-3.0.0/simgear/io/HTTPFileRequest.cxx --- simgear-2.10.0/simgear/io/HTTPFileRequest.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/HTTPFileRequest.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,91 @@ +// HTTP request writing response to a file. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "HTTPFileRequest.hxx" +#include +#include + +namespace simgear +{ +namespace HTTP +{ + + //---------------------------------------------------------------------------- + FileRequest::FileRequest(const std::string& url, const std::string& path): + Request(url, "GET"), + _filename(path) + { + + } + + //---------------------------------------------------------------------------- + void FileRequest::responseHeadersComplete() + { + Request::responseHeadersComplete(); + + if( responseCode() != 200 ) + return setFailure(responseCode(), responseReason()); + + if( !_filename.empty() ) + { + // TODO validate path? (would require to expose fgValidatePath somehow to + // simgear) + SGPath path(_filename); + path.create_dir(0755); + + _file.open(_filename.c_str(), std::ios::binary | std::ios::trunc); + } + + if( !_file ) + { + SG_LOG + ( + SG_IO, + SG_WARN, + "HTTP::FileRequest: failed to open file '" << _filename << "'" + ); + + abort("Failed to open file."); + } + } + + //---------------------------------------------------------------------------- + void FileRequest::gotBodyData(const char* s, int n) + { + if( !_file ) + { + SG_LOG + ( + SG_IO, + SG_DEBUG, + "HTTP::FileRequest: received data for closed file '" << _filename << "'" + ); + return; + } + + _file.write(s, n); + } + + //---------------------------------------------------------------------------- + void FileRequest::onAlways() + { + _file.close(); + } + +} // namespace HTTP +} // namespace simgear diff -Nru simgear-2.10.0/simgear/io/HTTPFileRequest.hxx simgear-3.0.0/simgear/io/HTTPFileRequest.hxx --- simgear-2.10.0/simgear/io/HTTPFileRequest.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/HTTPFileRequest.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,56 @@ +///@file HTTP request writing response to a file. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_HTTP_FILEREQUEST_HXX_ +#define SG_HTTP_FILEREQUEST_HXX_ + +#include "HTTPRequest.hxx" +#include + +namespace simgear +{ +namespace HTTP +{ + + class FileRequest: + public Request + { + public: + + /** + * + * @param url Adress to download from + * @param path Path to file for saving response + */ + FileRequest(const std::string& url, const std::string& path); + + protected: + std::string _filename; + std::ofstream _file; + + virtual void responseHeadersComplete(); + virtual void gotBodyData(const char* s, int n); + virtual void onAlways(); + }; + + typedef SGSharedPtr FileRequestRef; + +} // namespace HTTP +} // namespace simgear + +#endif /* SG_HTTP_FILEREQUEST_HXX_ */ diff -Nru simgear-2.10.0/simgear/io/httpget.cxx simgear-3.0.0/simgear/io/httpget.cxx --- simgear-2.10.0/simgear/io/httpget.cxx 2011-12-19 19:45:09.000000000 +0000 +++ simgear-3.0.0/simgear/io/httpget.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -48,35 +48,11 @@ } string key = h.substr(0, colonPos); - _headers[key] = h.substr(colonPos + 1); + requestHeader(key) = h.substr(colonPos + 1); } - virtual string_list requestHeaders() const - { - string_list r; - std::map::const_iterator it; - for (it = _headers.begin(); it != _headers.end(); ++it) { - r.push_back(it->first); - } - - return r; - } - - virtual string header(const string& name) const - { - std::map::const_iterator it = _headers.find(name); - if (it == _headers.end()) { - return string(); - } - - return it->second; - } protected: - virtual void responseHeadersComplete() - { - } - - virtual void responseComplete() + virtual void onDone() { _complete = true; } @@ -88,7 +64,6 @@ private: bool _complete; SGFile* _file; - std::map _headers; }; int main(int argc, char* argv[]) diff -Nru simgear-2.10.0/simgear/io/HTTPMemoryRequest.cxx simgear-3.0.0/simgear/io/HTTPMemoryRequest.cxx --- simgear-2.10.0/simgear/io/HTTPMemoryRequest.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/HTTPMemoryRequest.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,55 @@ +// HTTP request keeping response in memory. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "HTTPMemoryRequest.hxx" + +namespace simgear +{ +namespace HTTP +{ + + //---------------------------------------------------------------------------- + MemoryRequest::MemoryRequest(const std::string& url): + Request(url, "GET") + { + + } + + //---------------------------------------------------------------------------- + const std::string& MemoryRequest::responseBody() const + { + return _response; + } + + //---------------------------------------------------------------------------- + void MemoryRequest::responseHeadersComplete() + { + Request::responseHeadersComplete(); + + if( responseLength() ) + _response.reserve( responseLength() ); + } + + //---------------------------------------------------------------------------- + void MemoryRequest::gotBodyData(const char* s, int n) + { + _response.append(s, n); + } + +} // namespace HTTP +} // namespace simgear diff -Nru simgear-2.10.0/simgear/io/HTTPMemoryRequest.hxx simgear-3.0.0/simgear/io/HTTPMemoryRequest.hxx --- simgear-2.10.0/simgear/io/HTTPMemoryRequest.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/HTTPMemoryRequest.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,58 @@ +///@file HTTP request keeping response in memory. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_HTTP_MEMORYREQUEST_HXX_ +#define SG_HTTP_MEMORYREQUEST_HXX_ + +#include "HTTPRequest.hxx" +#include + +namespace simgear +{ +namespace HTTP +{ + + class MemoryRequest: + public Request + { + public: + + /** + * + * @param url Adress to download from + */ + MemoryRequest(const std::string& url); + + /** + * Body contents of server response. + */ + const std::string& responseBody() const; + + protected: + std::string _response; + + virtual void responseHeadersComplete(); + virtual void gotBodyData(const char* s, int n); + }; + + typedef SGSharedPtr MemoryRequestRef; + +} // namespace HTTP +} // namespace simgear + +#endif /* SG_HTTP_MEMORYREQUEST_HXX_ */ diff -Nru simgear-2.10.0/simgear/io/HTTPRequest.cxx simgear-3.0.0/simgear/io/HTTPRequest.cxx --- simgear-2.10.0/simgear/io/HTTPRequest.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/io/HTTPRequest.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -1,99 +1,190 @@ #include "HTTPRequest.hxx" -#include #include #include - -using std::string; -using std::map; +#include +#include +#include namespace simgear { - namespace HTTP { extern const int DEFAULT_HTTP_PORT; -Request::Request(const string& url, const string method) : - _method(method), - _url(url), - _responseVersion(HTTP_VERSION_UNKNOWN), - _responseStatus(0), - _responseLength(0), - _receivedBodyBytes(0), - _willClose(false) +//------------------------------------------------------------------------------ +Request::Request(const std::string& url, const std::string method): + _method(method), + _url(url), + _responseVersion(HTTP_VERSION_UNKNOWN), + _responseStatus(0), + _responseLength(0), + _receivedBodyBytes(0), + _ready_state(UNSENT), + _willClose(false) { - + } +//------------------------------------------------------------------------------ Request::~Request() { - + +} + +//------------------------------------------------------------------------------ +Request* Request::done(const Callback& cb) +{ + if( _ready_state == DONE ) + cb(this); + else + _cb_done = cb; + + return this; +} + +//------------------------------------------------------------------------------ +Request* Request::fail(const Callback& cb) +{ + if( _ready_state == FAILED ) + cb(this); + else + _cb_fail = cb; + + return this; +} + +//------------------------------------------------------------------------------ +Request* Request::always(const Callback& cb) +{ + if( isComplete() ) + cb(this); + else + _cb_always = cb; + + return this; +} + +//------------------------------------------------------------------------------ +void Request::setBodyData( const std::string& data, + const std::string& type ) +{ + _request_data = data; + _request_media_type = type; + + if( !data.empty() && _method == "GET" ) + _method = "POST"; +} + +//---------------------------------------------------------------------------- +void Request::setBodyData(const SGPropertyNode* data) +{ + if( !data ) + setBodyData(""); + + std::stringstream buf; + writeProperties(buf, data, true); + + setBodyData(buf.str(), "application/xml"); } -void Request::setUrl(const string& url) +//------------------------------------------------------------------------------ +void Request::setUrl(const std::string& url) { - _url = url; + _url = url; } -string_list Request::requestHeaders() const +//------------------------------------------------------------------------------ +void Request::requestStart() { - string_list r; - return r; + setReadyState(OPENED); } -string Request::header(const std::string& name) const +//------------------------------------------------------------------------------ +Request::HTTPVersion decodeHTTPVersion(const std::string& v) { - return string(); + if( v == "HTTP/1.1" ) return Request::HTTP_1_1; + if( v == "HTTP/1.0" ) return Request::HTTP_1_0; + if( strutils::starts_with(v, "HTTP/0.") ) return Request::HTTP_0_x; + return Request::HTTP_VERSION_UNKNOWN; } -void Request::responseStart(const string& r) +//------------------------------------------------------------------------------ +void Request::responseStart(const std::string& r) { const int maxSplit = 2; // HTTP/1.1 nnn reason-string string_list parts = strutils::split(r, NULL, maxSplit); if (parts.size() != 3) { - SG_LOG(SG_IO, SG_WARN, "HTTP::Request: malformed response start:" << r); - setFailure(400, "malformed HTTP response header"); - return; + throw sg_io_exception("bad HTTP response"); } - _responseVersion = decodeVersion(parts[0]); + _responseVersion = decodeHTTPVersion(parts[0]); _responseStatus = strutils::to_int(parts[1]); _responseReason = parts[2]; } -void Request::responseHeader(const string& key, const string& value) +//------------------------------------------------------------------------------ +void Request::responseHeader(const std::string& key, const std::string& value) { - if (key == "connection") { - _willClose = (value.find("close") != string::npos); - } - - _responseHeaders[key] = value; + if( key == "connection" ) + _willClose = (value.find("close") != std::string::npos); + + _responseHeaders[key] = value; } +//------------------------------------------------------------------------------ void Request::responseHeadersComplete() { - // no op + setReadyState(HEADERS_RECEIVED); } -void Request::processBodyBytes(const char* s, int n) +//------------------------------------------------------------------------------ +void Request::responseComplete() { - _receivedBodyBytes += n; - gotBodyData(s, n); + if( !isComplete() ) + setReadyState(DONE); } +//------------------------------------------------------------------------------ void Request::gotBodyData(const char* s, int n) { + setReadyState(LOADING); +} + +//------------------------------------------------------------------------------ +void Request::onDone() +{ } -void Request::responseComplete() +//------------------------------------------------------------------------------ +void Request::onFail() { - + SG_LOG + ( + SG_IO, + SG_INFO, + "request failed:" << url() << " : " + << responseCode() << "/" << responseReason() + ); } - -string Request::scheme() const + +//------------------------------------------------------------------------------ +void Request::onAlways() +{ + +} + +//------------------------------------------------------------------------------ +void Request::processBodyBytes(const char* s, int n) +{ + _receivedBodyBytes += n; + gotBodyData(s, n); +} + +//------------------------------------------------------------------------------ +std::string Request::scheme() const { int firstColon = url().find(":"); if (firstColon > 0) { @@ -102,10 +193,11 @@ return ""; // couldn't parse scheme } - -string Request::path() const + +//------------------------------------------------------------------------------ +std::string Request::path() const { - string u(url()); + std::string u(url()); int schemeEnd = u.find("://"); if (schemeEnd < 0) { return ""; // couldn't parse scheme @@ -127,10 +219,10 @@ return u.substr(hostEnd, query - hostEnd); } - -string Request::query() const +//------------------------------------------------------------------------------ +std::string Request::query() const { - string u(url()); + std::string u(url()); int query = u.find('?'); if (query < 0) { return ""; //no query string found @@ -139,105 +231,159 @@ return u.substr(query); //includes question mark } - - -string Request::host() const +//------------------------------------------------------------------------------ +std::string Request::host() const { - string hp(hostAndPort()); - int colonPos = hp.find(':'); - if (colonPos >= 0) { - return hp.substr(0, colonPos); // trim off the colon and port - } else { - return hp; // no port specifier - } + std::string hp(hostAndPort()); + int colonPos = hp.find(':'); + if (colonPos >= 0) { + return hp.substr(0, colonPos); // trim off the colon and port + } else { + return hp; // no port specifier + } } +//------------------------------------------------------------------------------ unsigned short Request::port() const { - string hp(hostAndPort()); - int colonPos = hp.find(':'); - if (colonPos >= 0) { - return (unsigned short) strutils::to_int(hp.substr(colonPos + 1)); - } else { - return DEFAULT_HTTP_PORT; - } + std::string hp(hostAndPort()); + int colonPos = hp.find(':'); + if (colonPos >= 0) { + return (unsigned short) strutils::to_int(hp.substr(colonPos + 1)); + } else { + return DEFAULT_HTTP_PORT; + } } -string Request::hostAndPort() const +//------------------------------------------------------------------------------ +std::string Request::hostAndPort() const { - string u(url()); - int schemeEnd = u.find("://"); - if (schemeEnd < 0) { - return ""; // couldn't parse scheme - } - - int hostEnd = u.find('/', schemeEnd + 3); - if (hostEnd < 0) { // all remainder of URL is host - return u.substr(schemeEnd + 3); - } - - return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3)); + std::string u(url()); + int schemeEnd = u.find("://"); + if (schemeEnd < 0) { + return ""; // couldn't parse scheme + } + + int hostEnd = u.find('/', schemeEnd + 3); + if (hostEnd < 0) { // all remainder of URL is host + return u.substr(schemeEnd + 3); + } + + return u.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3)); } +//------------------------------------------------------------------------------ void Request::setResponseLength(unsigned int l) { - _responseLength = l; + _responseLength = l; } +//------------------------------------------------------------------------------ unsigned int Request::responseLength() const { -// if the server didn't supply a content length, use the number -// of bytes we actually received (so far) - if ((_responseLength == 0) && (_receivedBodyBytes > 0)) { - return _receivedBodyBytes; - } - - return _responseLength; + // if the server didn't supply a content length, use the number + // of bytes we actually received (so far) + if( (_responseLength == 0) && (_receivedBodyBytes > 0) ) + return _receivedBodyBytes; + + return _responseLength; } +//------------------------------------------------------------------------------ void Request::setFailure(int code, const std::string& reason) { - _responseStatus = code; - _responseReason = reason; - failed(); + _responseStatus = code; + _responseReason = reason; + setReadyState(FAILED); +} + +//------------------------------------------------------------------------------ +void Request::setReadyState(ReadyState state) +{ + _ready_state = state; + if( state == DONE ) + { + // Finish C++ part of request to ensure everything is finished (for example + // files and streams are closed) before calling any callback (possibly using + // such files) + onDone(); + onAlways(); + + if( _cb_done ) + _cb_done(this); + } + else if( state == FAILED ) + { + onFail(); + onAlways(); + + if( _cb_fail ) + _cb_fail(this); + } + else + return; + + if( _cb_always ) + _cb_always(this); } -void Request::failed() +//------------------------------------------------------------------------------ +void Request::abort() { - // no-op in base class - SG_LOG(SG_IO, SG_INFO, "request failed:" << url()); + abort("Request aborted."); } -Request::HTTPVersion Request::decodeVersion(const string& v) +//---------------------------------------------------------------------------- +void Request::abort(const std::string& reason) { - if (v == "HTTP/1.1") return HTTP_1_1; - if (v == "HTTP/1.0") return HTTP_1_0; - if (strutils::starts_with(v, "HTTP/0.")) return HTTP_0_x; - return HTTP_VERSION_UNKNOWN; + if( isComplete() ) + return; + + setFailure(-1, reason); + _willClose = true; } +//------------------------------------------------------------------------------ bool Request::closeAfterComplete() const { -// for non HTTP/1.1 connections, assume server closes - return _willClose || (_responseVersion != HTTP_1_1); + // for non HTTP/1.1 connections, assume server closes + return _willClose || (_responseVersion != HTTP_1_1); } - -int Request::requestBodyLength() const + +//------------------------------------------------------------------------------ +bool Request::isComplete() const { - return -1; + return _ready_state == DONE || _ready_state == FAILED; } -std::string Request::requestBodyType() const +//------------------------------------------------------------------------------ +bool Request::hasBodyData() const { - return "text/plain"; + return !_request_media_type.empty(); } - -void Request::getBodyData(char*, int& count) const + +//------------------------------------------------------------------------------ +std::string Request::bodyType() const { - count = 0; - return; + return _request_media_type; } -} // of namespace HTTP +//------------------------------------------------------------------------------ +size_t Request::bodyLength() const +{ + return _request_data.length(); +} +//------------------------------------------------------------------------------ +size_t Request::getBodyData(char* s, size_t offset, size_t max_count) const +{ + size_t bytes_available = _request_data.size() - offset; + size_t bytes_to_read = std::min(bytes_available, max_count); + + memcpy(s, _request_data.data() + offset, bytes_to_read); + + return bytes_to_read; +} + +} // of namespace HTTP } // of namespace simgear diff -Nru simgear-2.10.0/simgear/io/HTTPRequest.hxx simgear-3.0.0/simgear/io/HTTPRequest.hxx --- simgear-2.10.0/simgear/io/HTTPRequest.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/io/HTTPRequest.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -3,21 +3,85 @@ #include +#include #include #include #include +#include + +class SGPropertyNode; + namespace simgear { - namespace HTTP { -class Request : public SGReferenced +class Request: + public SGReferenced { public: + typedef boost::function Callback; + + enum ReadyState + { + UNSENT = 0, + OPENED, + HEADERS_RECEIVED, + LOADING, + DONE, + FAILED + }; + virtual ~Request(); - + + /** + * + */ + StringMap& requestHeaders() { return _request_headers; } + const StringMap& requestHeaders() const { return _request_headers; } + std::string& requestHeader(const std::string& key) + { return _request_headers[key]; } + const std::string requestHeader(const std::string& key) const + { return _request_headers.get(key); } + + /** + * Set the handler to be called when the request successfully completes. + * + * @note If the request is already complete, the handler is called + * immediately. + */ + Request* done(const Callback& cb); + + /** + * Set the handler to be called when the request completes or aborts with an + * error. + * + * @note If the request has already failed, the handler is called + * immediately. + */ + Request* fail(const Callback& cb); + + /** + * Set the handler to be called when the request either successfully + * completes or fails. + * + * @note If the request is already complete or has already failed, the + * handler is called immediately. + */ + Request* always(const Callback& cb); + + /** + * Set the data for the body of the request. The request is automatically + * send using the POST method. + * + * @param data Body data + * @param type Media Type (aka MIME) of the body data + */ + void setBodyData( const std::string& data, + const std::string& type = "text/plain" ); + void setBodyData( const SGPropertyNode* data ); + virtual void setUrl(const std::string& url); virtual std::string method() const @@ -32,8 +96,8 @@ virtual unsigned short port() const; virtual std::string query() const; - virtual string_list requestHeaders() const; - virtual std::string header(const std::string& name) const; + StringMap const& responseHeaders() const + { return _responseHeaders; } virtual int responseCode() const { return _responseStatus; } @@ -41,26 +105,30 @@ virtual std::string responseReason() const { return _responseReason; } - void setResponseLength(unsigned int l); + void setResponseLength(unsigned int l); virtual unsigned int responseLength() const; /** - * Query the size of the request body. -1 (the default value) means no - * request body + * Check if request contains body data. + */ + virtual bool hasBodyData() const; + + /** + * Retrieve the request body content type. */ - virtual int requestBodyLength() const; + virtual std::string bodyType() const; + + /** + * Retrieve the size of the request body. + */ + virtual size_t bodyLength() const; /** * Retrieve the body data bytes. Will be passed the maximum body bytes - * to return in the buffer, and should update count with the actual number + * to return in the buffer, and must return the actual number * of bytes written. */ - virtual void getBodyData(char* s, int& count) const; - - /** - * retrieve the request body content type. Default is text/plain - */ - virtual std::string requestBodyType() const; + virtual size_t getBodyData(char* s, size_t offset, size_t max_count) const; /** * running total of body bytes received so far. Can be used @@ -80,43 +148,72 @@ HTTPVersion responseVersion() const { return _responseVersion; } - static HTTPVersion decodeVersion(const std::string& v); - + ReadyState readyState() const { return _ready_state; } + + /** + * Request aborting this request. + */ + void abort(); + + /** + * Request aborting this request and specify the reported reaseon for it. + */ + void abort(const std::string& reason); + bool closeAfterComplete() const; + bool isComplete() const; + protected: Request(const std::string& url, const std::string method = "GET"); + virtual void requestStart(); virtual void responseStart(const std::string& r); virtual void responseHeader(const std::string& key, const std::string& value); virtual void responseHeadersComplete(); virtual void responseComplete(); - virtual void failed(); virtual void gotBodyData(const char* s, int n); + + virtual void onDone(); + virtual void onFail(); + virtual void onAlways(); + + void setFailure(int code, const std::string& reason); + private: friend class Client; friend class Connection; + friend class ContentDecoder; + Request(const Request&); // = delete; + Request& operator=(const Request&); // = delete; + void processBodyBytes(const char* s, int n); - void setFailure(int code, const std::string& reason); + void setReadyState(ReadyState state); - std::string _method; - std::string _url; - HTTPVersion _responseVersion; - int _responseStatus; - std::string _responseReason; - unsigned int _responseLength; - unsigned int _receivedBodyBytes; - bool _willClose; - - typedef std::map HeaderDict; - HeaderDict _responseHeaders; + std::string _method; + std::string _url; + StringMap _request_headers; + std::string _request_data; + std::string _request_media_type; + + HTTPVersion _responseVersion; + int _responseStatus; + std::string _responseReason; + StringMap _responseHeaders; + unsigned int _responseLength; + unsigned int _receivedBodyBytes; + + Callback _cb_done, + _cb_fail, + _cb_always; + + ReadyState _ready_state; + bool _willClose; }; typedef SGSharedPtr Request_ptr; } // of namespace HTTP - } // of namespace simgear #endif // of SG_HTTP_REQUEST_HXX - diff -Nru simgear-2.10.0/simgear/io/http_svn.cxx simgear-3.0.0/simgear/io/http_svn.cxx --- simgear-2.10.0/simgear/io/http_svn.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/http_svn.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,51 @@ +#include +#include +#include + +#include +#include + + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace simgear; +using std::cout; +using std::endl; +using std::cerr; +using std::string; + +HTTP::Client* httpClient; + +int main(int argc, char* argv[]) +{ + sglog().setLogLevels( SG_ALL, SG_INFO ); + HTTP::Client cl; + httpClient = &cl; + + + SGPath p("/Users/jmt/Desktop/traffic"); + SVNRepository airports(p, &cl); + // airports.setBaseUrl("http://svn.goneabitbursar.com/testproject1"); +// airports.setBaseUrl("http://terrascenery.googlecode.com/svn/trunk/data/Scenery/Models"); + + airports.setBaseUrl("http://fgfs.goneabitbursar.com/fgfsai/trunk/AI/Traffic"); + +// airports.setBaseUrl("http://terrascenery.googlecode.com/svn/trunk/data/Scenery/Airports"); + airports.update(); + + while (airports.isDoingSync()) { + cl.update(100); + } + + cout << "all done!" << endl; + return EXIT_SUCCESS; +} \ No newline at end of file diff -Nru simgear-2.10.0/simgear/io/raw_socket.cxx simgear-3.0.0/simgear/io/raw_socket.cxx --- simgear-2.10.0/simgear/io/raw_socket.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/io/raw_socket.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -454,6 +454,23 @@ #endif } +#ifdef SO_NOSIGPIPE + // Do not generate SIGPIPE signal (which immediately terminates the program), + // instead ::send() will return -1 and errno will be set to EPIPE. + // SO_NOSIGPIPE should be available on Mac/BSD systems, but is not available + // within Posix/Linux. + // This only works for calls to ::send() but not for ::write(): + // http://freebsd.1045724.n5.nabble.com/is-setsockopt-SO-NOSIGPIPE-work-tp4011054p4011055.html + int set = 1; + setsockopt(handle, SOL_SOCKET, SO_NOSIGPIPE, (void*)&set, sizeof(set)); +#endif + +#ifndef MSG_NOSIGNAL +# define MSG_NOSIGNAL 0 +#endif + // TODO supress SIGPIPE if neither SO_NOSIGPIPE nor MSG_NOSIGNAL is available + // http://krokisplace.blogspot.co.at/2010/02/suppressing-sigpipe-in-library.html + return (handle != -1); } @@ -592,7 +609,7 @@ int Socket::send (const void * buffer, int size, int flags) { assert ( handle != -1 ) ; - return ::send (handle, (const char*)buffer, size, flags); + return ::send (handle, (const char*)buffer, size, flags | MSG_NOSIGNAL); } @@ -600,8 +617,12 @@ int flags, const IPAddress* to ) { assert ( handle != -1 ) ; - return ::sendto(handle,(const char*)buffer,size,flags, - (const sockaddr*) to->getAddr(), to->getAddrLen()); + return ::sendto( handle, + (const char*)buffer, + size, + flags | MSG_NOSIGNAL, + (const sockaddr*)to->getAddr(), + to->getAddrLen() ); } diff -Nru simgear-2.10.0/simgear/io/sg_binobj.cxx simgear-3.0.0/simgear/io/sg_binobj.cxx --- simgear-2.10.0/simgear/io/sg_binobj.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/io/sg_binobj.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -43,6 +43,7 @@ #include #include #include +#include #include "lowlevel.hxx" #include "sg_binobj.hxx" @@ -319,15 +320,18 @@ } if ( sgReadError() ) { - cout << "We detected an error reading object properties" << endl; - return; + throw sg_exception("Error reading object properties"); + } + + size_t indexCount = std::bitset<32>(idx_mask).count(); + if (indexCount == 0) { + throw sg_exception("object index mask has no bits set"); } for ( j = 0; j < nelements; ++j ) { sgReadUInt( fp, &nbytes ); if ( sgReadError() ) { - cout << "We detected an error reading element size for :" << j << endl; - return; + throw sg_exception("Error reading element size"); } buf.resize( nbytes ); @@ -335,8 +339,7 @@ sgReadBytes( fp, nbytes, ptr ); if ( sgReadError() ) { - cout << "We detected an error reading object element:" << j << "bytes="<< nbytes << endl; - return; + throw sg_exception("Error reading element bytes"); } int_list vs; @@ -405,7 +408,7 @@ SG_LOG( SG_EVENT, SG_ALERT, "ERROR: opening " << file << " or " << filegz << " for reading!"); - return false; + throw sg_io_exception("Error opening for reading (and .gz)", sg_location(file)); } } @@ -423,9 +426,7 @@ } else { // close the file before we return gzclose(fp); - SG_LOG( SG_EVENT, SG_ALERT, - "ERROR: " << file << "has bad header"); - return false; + throw sg_io_exception("Bad BTG magic/version", sg_location(file)); } // read creation time @@ -462,8 +463,7 @@ //cout << "Total objects to read = " << nobjects << endl; if ( sgReadError() ) { - cout << "Error while reading header of file " << file << "(.gz)" << endl; - return false; + throw sg_io_exception("Error reading BTG file header", sg_location(file)); } // read in objects @@ -613,19 +613,13 @@ } if ( sgReadError() ) { - cout << "Error while reading object:" << i << " in file " << file << "(.gz)" << endl; - return false; + throw sg_io_exception("Error while reading object", sg_location(file, i)); } } // close the file gzclose(fp); - if ( sgReadError() ) { - cout << "Error while reading file " << file << "(.gz)" << endl; - return false; - } - return true; } @@ -665,7 +659,7 @@ if (verts.empty()) { return; } - + unsigned int start = 0, end = 1; string m; int_list emptyList; @@ -688,6 +682,13 @@ if ( !normals.empty() && !normals.front().empty()) idx_mask |= SG_IDX_NORMALS; if ( !colors.empty() && !colors.front().empty()) idx_mask |= SG_IDX_COLORS; if ( !texCoords.empty() && !texCoords.front().empty()) idx_mask |= SG_IDX_TEXCOORDS; + + if (idx_mask == 0) { + SG_LOG(SG_IO, SG_ALERT, "SGBinObject::write_objects: object with material:" + << m << "has no indices set"); + } + + sgWriteChar( fp, (char)SG_INDEX_TYPES ); // property sgWriteUInt( fp, 1 ); // nbytes sgWriteChar( fp, idx_mask ); @@ -934,7 +935,7 @@ fprintf(fp, "\n"); // dump individual triangles if they exist - if ( tris_v.size() > 0 ) { + if ( ! tris_v.empty() ) { fprintf(fp, "# triangle groups\n"); int start = 0; @@ -982,7 +983,7 @@ } // dump triangle groups - if ( strips_v.size() > 0 ) { + if ( ! strips_v.empty() ) { fprintf(fp, "# triangle strips\n"); int start = 0; diff -Nru simgear-2.10.0/simgear/io/sg_netChannel.cxx simgear-3.0.0/simgear/io/sg_netChannel.cxx --- simgear-2.10.0/simgear/io/sg_netChannel.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/io/sg_netChannel.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -41,8 +41,6 @@ namespace simgear { -static NetChannel* channels = 0 ; - NetChannel::NetChannel () { closed = true ; @@ -51,31 +49,14 @@ accepting = false ; write_blocked = false ; should_delete = false ; - - next_channel = channels ; - channels = this ; + poller = NULL; } NetChannel::~NetChannel () { close(); - - NetChannel* prev = NULL ; - - for ( NetChannel* ch = channels; ch != NULL; - ch = ch -> next_channel ) - { - if (ch == this) - { - ch = ch -> next_channel ; - if ( prev != NULL ) - prev -> next_channel = ch ; - else - channels = ch ; - next_channel = 0 ; - break; - } - prev = ch ; + if (poller) { + poller->removeChannel(this); } } @@ -232,89 +213,6 @@ } } -bool -NetChannel::poll (unsigned int timeout) -{ - if (!channels) - return false ; - - enum { MAX_SOCKETS = 256 } ; - Socket* reads [ MAX_SOCKETS+1 ] ; - Socket* writes [ MAX_SOCKETS+1 ] ; - Socket* deletes [ MAX_SOCKETS+1 ] ; - int nreads = 0 ; - int nwrites = 0 ; - int ndeletes = 0 ; - int nopen = 0 ; - NetChannel* ch; - for ( ch = channels; ch != NULL; ch = ch -> next_channel ) - { - if ( ch -> should_delete ) - { - assert(ndeletes closed ) - { - if (ch -> resolving_host ) - { - ch -> handleResolve(); - continue; - } - - nopen++ ; - if (ch -> readable()) { - assert(nreads writable()) { - assert(nwrites closed ) - ch -> handleReadEvent(); - } - - for ( i=0; writes[i]; i++ ) - { - ch = (NetChannel*)writes[i]; - if ( ! ch -> closed ) - ch -> handleWriteEvent(); - } - - return true ; -} - -void -NetChannel::loop (unsigned int timeout) -{ - while ( poll (timeout) ) ; -} - - void NetChannel::handleRead (void) { SG_LOG(SG_IO, SG_WARN, "Network:" << getHandle() << ": unhandled read"); } @@ -336,4 +234,114 @@ } } +void +NetChannelPoller::addChannel(NetChannel* channel) +{ + assert(channel); + assert(channel->poller == NULL); + + channel->poller = this; + channels.push_back(channel); +} + +void +NetChannelPoller::removeChannel(NetChannel* channel) +{ + assert(channel); + assert(channel->poller == this); + channel->poller = NULL; + + ChannelList::iterator it = channels.begin(); + for (; it != channels.end(); ++it) { + if (*it == channel) { + channels.erase(it); + return; + } + } +} + +bool +NetChannelPoller::poll(unsigned int timeout) +{ + if (channels.empty()) { + return false; + } + + enum { MAX_SOCKETS = 256 } ; + Socket* reads [ MAX_SOCKETS+1 ] ; + Socket* writes [ MAX_SOCKETS+1 ] ; + int nreads = 0 ; + int nwrites = 0 ; + int nopen = 0 ; + + ChannelList::iterator it = channels.begin(); + while( it != channels.end() ) + { + NetChannel* ch = *it; + if ( ch -> should_delete ) + { + // avoid the channel trying to remove itself from us, or we get + // bug http://code.google.com/p/flightgear-bugs/issues/detail?id=1144 + ch->poller = NULL; + delete ch; + it = channels.erase(it); + continue; + } + + ++it; // we've copied the pointer into ch + if ( ch->closed ) { + continue; + } + + if (ch -> resolving_host ) + { + ch -> handleResolve(); + continue; + } + + nopen++ ; + if (ch -> readable()) { + assert(nreads writable()) { + assert(nwrites closed ) + ch -> handleReadEvent(); + } + + for ( int i=0; writes[i]; i++ ) + { + NetChannel* ch = (NetChannel*)writes[i]; + if ( ! ch -> closed ) + ch -> handleWriteEvent(); + } + + return true ; +} + +void +NetChannelPoller::loop (unsigned int timeout) +{ + while ( poll (timeout) ) ; +} + + } // of namespace simgear diff -Nru simgear-2.10.0/simgear/io/sg_netChannel.hxx simgear-3.0.0/simgear/io/sg_netChannel.hxx --- simgear-2.10.0/simgear/io/sg_netChannel.hxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/io/sg_netChannel.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -54,20 +54,23 @@ #define SG_NET_CHANNEL_H #include + #include +#include namespace simgear { +class NetChannelPoller; + class NetChannel : public Socket { bool closed, connected, accepting, write_blocked, should_delete, resolving_host ; - NetChannel* next_channel ; std::string host; int port; - friend bool netPoll (unsigned int timeout); - + friend class NetChannelPoller; + NetChannelPoller* poller; public: NetChannel () ; @@ -109,9 +112,21 @@ virtual void handleWrite (void); virtual void handleAccept (void); virtual void handleError (int error); - - static bool poll (unsigned int timeout = 0 ) ; - static void loop (unsigned int timeout = 0 ) ; + +}; + +class NetChannelPoller +{ + typedef std::vector ChannelList; + ChannelList channels; +public: + void addChannel(NetChannel* channel); + void removeChannel(NetChannel* channel); + + bool hasChannels() const { return !channels.empty(); } + + bool poll(unsigned int timeout = 0); + void loop(unsigned int timeout = 0); }; } // of namespace simgear diff -Nru simgear-2.10.0/simgear/io/sg_netChat.cxx simgear-3.0.0/simgear/io/sg_netChat.cxx --- simgear-2.10.0/simgear/io/sg_netChat.cxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/io/sg_netChat.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -25,31 +25,29 @@ #include -#include // for strdup +#include #include namespace simgear { void -NetChat::setTerminator (const char* t) +NetChat::setTerminator(const std::string& t) { - if (terminator) free(terminator); - terminator = strdup(t); + terminator = t; bytesToCollect = -1; } const char* -NetChat::getTerminator (void) +NetChat::getTerminator() const { - return terminator; + return terminator.c_str(); } void NetChat::setByteCount(int count) { - if (terminator) free(terminator); - terminator = NULL; + terminator.clear(); bytesToCollect = count; } @@ -59,15 +57,15 @@ #define MAX(a,b) (((a)>(b))?(a):(b)) static int -find_prefix_at_end (const NetBuffer& haystack, const char* needle) +find_prefix_at_end(const NetBuffer& haystack, const std::string& needle) { const char* hd = haystack.getData(); int hl = haystack.getLength(); - int nl = strlen(needle); + int nl = needle.length(); for (int i = MAX (nl-hl, 0); i < nl; i++) { //if (haystack.compare (needle, hl-(nl-i), nl-i) == 0) { - if (memcmp(needle, &hd[hl-(nl-i)], nl-i) == 0) { + if (memcmp(needle.c_str(), &hd[hl-(nl-i)], nl-i) == 0) { return (nl-i); } } @@ -75,12 +73,12 @@ } static int -find_terminator (const NetBuffer& haystack, const char* needle) +find_terminator(const NetBuffer& haystack, const std::string& needle) { - if (needle && *needle) + if( !needle.empty() ) { const char* data = haystack.getData(); - const char* ptr = strstr(data,needle); + const char* ptr = strstr(data,needle.c_str()); if (ptr != NULL) return(ptr-data); } @@ -102,7 +100,7 @@ while (in_buffer.getLength()) { // special case where we're not using a terminator - if (terminator == 0 || *terminator == 0) { + if ( terminator.empty() ) { if ( bytesToCollect > 0) { const int toRead = std::min(in_buffer.getLength(), bytesToCollect); collectIncomingData(in_buffer.getData(), toRead); @@ -119,8 +117,6 @@ continue; } - int terminator_len = strlen(terminator); - int index = find_terminator ( in_buffer, terminator ) ; // 3 cases: @@ -134,7 +130,7 @@ if (index != -1) { // we found the terminator collectIncomingData ( in_buffer.getData(), index ) ; - in_buffer.remove (0, index + terminator_len); + in_buffer.remove (0, index + terminator.length()); foundTerminator(); } else { // check for a prefix of the terminator diff -Nru simgear-2.10.0/simgear/io/sg_netChat.hxx simgear-3.0.0/simgear/io/sg_netChat.hxx --- simgear-2.10.0/simgear/io/sg_netChat.hxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/io/sg_netChat.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -61,8 +61,6 @@ #ifndef SG_NET_CHAT_H #define SG_NET_CHAT_H -#include -#include #include namespace simgear @@ -70,19 +68,20 @@ class NetChat : public NetBufferChannel { - char* terminator; + std::string terminator; int bytesToCollect; + +protected: virtual void handleBufferRead (NetBuffer& buffer) ; public: - NetChat () : - terminator (NULL), + NetChat () : bytesToCollect(-1) {} - void setTerminator (const char* t); - const char* getTerminator (void); + void setTerminator(const std::string& t); + const char* getTerminator() const; /** * set byte count to collect - 'foundTerminator' will be called once diff -Nru simgear-2.10.0/simgear/io/sg_serial.hxx simgear-3.0.0/simgear/io/sg_serial.hxx --- simgear-2.10.0/simgear/io/sg_serial.hxx 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/io/sg_serial.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -40,15 +40,13 @@ #include "iochannel.hxx" -using std::string; - /** * A serial I/O class based on SGIOChannel. */ class SGSerial : public SGIOChannel { - string device; - string baud; + std::string device; + std::string baud; SGSerialPort port; char save_buf[ 2 * SG_IO_MAX_MSG_SIZE ]; @@ -68,7 +66,7 @@ * @param device_name name of serial device * @param baud_rate speed of communication */ - SGSerial( const string& device_name, const string& baud_rate ); + SGSerial( const std::string& device_name, const std::string& baud_rate ); /** Destructor */ ~SGSerial(); diff -Nru simgear-2.10.0/simgear/io/sg_socket_udp.cxx simgear-3.0.0/simgear/io/sg_socket_udp.cxx --- simgear-2.10.0/simgear/io/sg_socket_udp.cxx 2012-01-04 20:12:22.000000000 +0000 +++ simgear-3.0.0/simgear/io/sg_socket_udp.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -103,9 +103,14 @@ return 0; } + if (length <= 0) { + return 0; + } int result; + // prevent buffer overflow + int maxsize = std::min(length - 1, SG_IO_MAX_MSG_SIZE); - if ( (result = sock.recv(buf, SG_IO_MAX_MSG_SIZE, 0)) >= 0 ) { + if ( (result = sock.recv(buf, maxsize, 0)) >= 0 ) { buf[result] = '\0'; // printf("msg received = %s\n", buf); } @@ -120,10 +125,16 @@ return 0; } + if (length <= 0) { + return 0; + } // cout << "sock = " << sock << endl; char *buf_ptr = save_buf + save_len; - int result = sock.recv(buf_ptr, SG_IO_MAX_MSG_SIZE, 0); + // prevent buffer overflow (size of save_buf is 2 * SG_IO_MAX_MSG_SIZE) + int maxsize = save_len < SG_IO_MAX_MSG_SIZE ? + SG_IO_MAX_MSG_SIZE : 2 * SG_IO_MAX_MSG_SIZE - save_len; + int result = sock.recv(buf_ptr, maxsize, 0); // printf("msg received = %s\n", buf); save_len += result; @@ -142,6 +153,8 @@ // we found an end of line // copy to external buffer + // prevent buffer overflow + result = std::min(result,length - 1); strncpy( buf, save_buf, result ); buf[result] = '\0'; // cout << "sg_socket line = " << buf << endl; diff -Nru simgear-2.10.0/simgear/io/SVNDirectory.cxx simgear-3.0.0/simgear/io/SVNDirectory.cxx --- simgear-2.10.0/simgear/io/SVNDirectory.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/SVNDirectory.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,383 @@ + +#include "SVNDirectory.hxx" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::string; +using std::cout; +using std::endl; +using namespace simgear; + +typedef std::vector RequestVector; +typedef std::map DAVResourceMap; + + +const char* DAV_CACHE_NAME = ".terrasync_cache"; +const char* CACHE_VERSION_4_TOKEN = "terrasync-cache-4"; + +// important: with the Google servers, setting this higher than '1' causes +// server internal errors (500, the connection is closed). In other words we +// can only specify update report items one level deep at most and no more. +// (the root and its direct children, not NOT grand-children) +const unsigned int MAX_UPDATE_REPORT_DEPTH = 1; + +enum LineState +{ + LINESTATE_HREF = 0, + LINESTATE_VERSIONNAME +}; + +SVNDirectory::SVNDirectory(SVNRepository *r, const SGPath& path) : + localPath(path), + dav(NULL), + repo(r), + _doingUpdateReport(false), + _parent(NULL) +{ + if (path.exists()) { + parseCache(); + } + + // don't create dir here, repo might not exist at all +} + +SVNDirectory::SVNDirectory(SVNDirectory* pr, DAVCollection* col) : + dav(col), + repo(pr->repository()), + _doingUpdateReport(false), + _parent(pr) +{ + assert(col->container()); + assert(!col->url().empty()); + assert(_parent); + + localPath = pr->fsDir().file(col->name()); + if (!localPath.exists()) { + Dir d(localPath); + d.create(0755); + writeCache(); + } else { + parseCache(); + } +} + +SVNDirectory::~SVNDirectory() +{ + // recursive delete our child directories + BOOST_FOREACH(SVNDirectory* d, _children) { + delete d; + } +} + +void SVNDirectory::parseCache() +{ + SGPath p(localPath); + p.append(DAV_CACHE_NAME); + if (!p.exists()) { + return; + } + + char href[1024]; + char versionName[128]; + LineState lineState = LINESTATE_HREF; + std::ifstream file(p.c_str()); + if (!file.is_open()) { + SG_LOG(SG_IO, SG_WARN, "unable to open cache file for reading:" << p); + return; + } + bool doneSelf = false; + + file.getline(href, 1024); + if (strcmp(CACHE_VERSION_4_TOKEN, href)) { + SG_LOG(SG_IO, SG_WARN, "invalid cache file [missing header token]:" << p << " '" << href << "'"); + return; + } + + std::string vccUrl; + file.getline(href, 1024); + vccUrl = href; + + while (!file.eof()) { + if (lineState == LINESTATE_HREF) { + file.getline(href, 1024); + lineState = LINESTATE_VERSIONNAME; + } else { + assert(lineState == LINESTATE_VERSIONNAME); + file.getline(versionName, 1024); + lineState = LINESTATE_HREF; + char* hrefPtr = href; + + if (!doneSelf) { + if (!dav) { + dav = new DAVCollection(hrefPtr); + dav->setVersionName(versionName); + } else { + assert(string(hrefPtr) == dav->url()); + } + + if (!vccUrl.empty()) { + dav->setVersionControlledConfiguration(vccUrl); + } + + _cachedRevision = versionName; + doneSelf = true; + } else { + DAVResource* child = addChildDirectory(hrefPtr)->collection(); + string s = strutils::strip(versionName); + if (!s.empty()) { + child->setVersionName(versionName); + } + } // of done self test + } // of line-state switching + } // of file get-line loop +} + +void SVNDirectory::writeCache() +{ + SGPath p(localPath); + if (!p.exists()) { + Dir d(localPath); + d.create(0755); + } + + p.append(string(DAV_CACHE_NAME) + ".new"); + + std::ofstream file(p.c_str(), std::ios::trunc); +// first, cache file version header + file << CACHE_VERSION_4_TOKEN << '\n'; + +// second, the repository VCC url + file << dav->versionControlledConfiguration() << '\n'; + +// third, our own URL, and version + file << dav->url() << '\n' << _cachedRevision << '\n'; + + BOOST_FOREACH(DAVResource* child, dav->contents()) { + if (child->isCollection()) { + file << child->name() << '\n' << child->versionName() << "\n"; + } + } // of child iteration + + file.close(); + +// approximately atomic delete + rename operation + SGPath cacheName(localPath); + cacheName.append(DAV_CACHE_NAME); + p.rename(cacheName); +} + +void SVNDirectory::setBaseUrl(const string& url) +{ + if (_parent) { + SG_LOG(SG_IO, SG_ALERT, "setting base URL on non-root directory " << url); + return; + } + + if (dav && (url == dav->url())) { + return; + } + + dav = new DAVCollection(url); +} + +std::string SVNDirectory::url() const +{ + if (!_parent) { + return repo->baseUrl(); + } + + return _parent->url() + "/" + name(); +} + +std::string SVNDirectory::name() const +{ + return dav->name(); +} + +DAVResource* +SVNDirectory::addChildFile(const std::string& fileName) +{ + DAVResource* child = NULL; + child = new DAVResource(dav->urlForChildWithName(fileName)); + dav->addChild(child); + + writeCache(); + return child; +} + +SVNDirectory* +SVNDirectory::addChildDirectory(const std::string& dirName) +{ + if (dav->childWithName(dirName)) { + // existing child, let's remove it + deleteChildByName(dirName); + } + + DAVCollection* childCol = dav->createChildCollection(dirName); + SVNDirectory* child = new SVNDirectory(this, childCol); + childCol->setVersionName(child->cachedRevision()); + _children.push_back(child); + writeCache(); + return child; +} + +void SVNDirectory::deleteChildByName(const std::string& nm) +{ + DAVResource* child = dav->childWithName(nm); + if (!child) { +// std::cerr << "ZZZ: deleteChildByName: unknown:" << nm << std::endl; + return; + } + + SGPath path = fsDir().file(nm); + + if (child->isCollection()) { + Dir d(path); + d.remove(true); + + DirectoryList::iterator it = findChildDir(nm); + if (it != _children.end()) { + SVNDirectory* c = *it; + // std::cout << "YYY: deleting SVNDirectory for:" << nm << std::endl; + delete c; + _children.erase(it); + } + } else { + path.remove(); + } + + dav->removeChild(child); + delete child; + + writeCache(); +} + +bool SVNDirectory::isDoingSync() const +{ + if (_doingUpdateReport) { + return true; + } + + BOOST_FOREACH(SVNDirectory* child, _children) { + if (child->isDoingSync()) { + return true; + } // of children + } + + return false; +} + +void SVNDirectory::beginUpdateReport() +{ + _doingUpdateReport = true; + _cachedRevision.clear(); + writeCache(); +} + +void SVNDirectory::updateReportComplete() +{ + _cachedRevision = dav->versionName(); + _doingUpdateReport = false; + writeCache(); + + SVNDirectory* pr = parent(); + if (pr) { + pr->writeCache(); + } +} + +SVNRepository* SVNDirectory::repository() const +{ + return repo; +} + +void SVNDirectory::mergeUpdateReportDetails(unsigned int depth, + string_list& items) +{ + // normal, easy case: we are fully in-sync at a revision + if (!_cachedRevision.empty()) { + std::ostringstream os; + os << "" + << repoPath() << ""; + items.push_back(os.str()); + return; + } + + Dir d(localPath); + if (depth >= MAX_UPDATE_REPORT_DEPTH) { + d.removeChildren(); + return; + } + + PathList cs = d.children(Dir::NO_DOT_OR_DOTDOT | Dir::INCLUDE_HIDDEN | Dir::TYPE_DIR); + BOOST_FOREACH(SGPath path, cs) { + SVNDirectory* c = child(path.file()); + if (!c) { + // ignore this child, if it's an incomplete download, + // it will be over-written on the update anyway + //std::cerr << "unknown SVN child" << path << std::endl; + } else { + // recurse down into children + c->mergeUpdateReportDetails(depth+1, items); + } + } // of child dir iteration +} + +std::string SVNDirectory::repoPath() const +{ + if (!_parent) { + return "/"; + } + + // find the length of the repository base URL, then + // trim that off our repo URL - job done! + size_t baseUrlLen = repo->baseUrl().size(); + return dav->url().substr(baseUrlLen + 1); +} + +SVNDirectory* SVNDirectory::parent() const +{ + return _parent; +} + +SVNDirectory* SVNDirectory::child(const std::string& dirName) const +{ + BOOST_FOREACH(SVNDirectory* d, _children) { + if (d->name() == dirName) { + return d; + } + } + + return NULL; +} + +DirectoryList::iterator +SVNDirectory::findChildDir(const std::string& dirName) +{ + DirectoryList::iterator it; + for (it=_children.begin(); it != _children.end(); ++it) { + if ((*it)->name() == dirName) { + return it; + } + } + return it; +} + +simgear::Dir SVNDirectory::fsDir() const +{ + return Dir(localPath); +} diff -Nru simgear-2.10.0/simgear/io/SVNDirectory.hxx simgear-3.0.0/simgear/io/SVNDirectory.hxx --- simgear-2.10.0/simgear/io/SVNDirectory.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/SVNDirectory.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,108 @@ +// DAVCollectionMirror.hxx - mirror a DAV collection to the local filesystem +// +// Copyright (C) 2013 James Turner +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +#ifndef SG_IO_DAVCOLLECTIONMIRROR_HXX +#define SG_IO_DAVCOLLECTIONMIRROR_HXX + +#include +#include +#include + +#include +#include +#include + +namespace simgear { + +class Dir; +namespace HTTP { class Request; } + +// forward decls +class DAVMirror; +class SVNRepository; +class SVNDirectory; + +typedef std::vector DirectoryList; + +class SVNDirectory +{ +public: + // init from local + SVNDirectory(SVNRepository *repo, const SGPath& path); + ~SVNDirectory(); + + void setBaseUrl(const std::string& url); + + // init from a collection + SVNDirectory(SVNDirectory* pr, DAVCollection* col); + + void beginUpdateReport(); + void updateReportComplete(); + + bool isDoingSync() const; + + std::string url() const; + + std::string name() const; + + DAVResource* addChildFile(const std::string& fileName); + SVNDirectory* addChildDirectory(const std::string& dirName); + + // void updateChild(DAVResource* child); + void deleteChildByName(const std::string& name); + + SGPath fsPath() const + { return localPath; } + + simgear::Dir fsDir() const; + + std::string repoPath() const; + + SVNRepository* repository() const; + DAVCollection* collection() const + { return dav; } + + std::string cachedRevision() const + { return _cachedRevision; } + + void mergeUpdateReportDetails(unsigned int depth, string_list& items); + + SVNDirectory* parent() const; + SVNDirectory* child(const std::string& dirName) const; +private: + + void parseCache(); + void writeCache(); + + DirectoryList::iterator findChildDir(const std::string& dirName); + + SGPath localPath; + DAVCollection* dav; + SVNRepository* repo; + + std::string _cachedRevision; + bool _doingUpdateReport; + + SVNDirectory* _parent; + DirectoryList _children; +}; + +} // of namespace simgear + +#endif // of SG_IO_DAVCOLLECTIONMIRROR_HXX diff -Nru simgear-2.10.0/simgear/io/SVNReportParser.cxx simgear-3.0.0/simgear/io/SVNReportParser.cxx --- simgear-2.10.0/simgear/io/SVNReportParser.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/SVNReportParser.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,605 @@ +// SVNReportParser -- parser for SVN report XML data +// +// Copyright (C) 2012 James Turner +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "SVNReportParser.hxx" + +#include +#include +#include +#include +#include +#include + +#include + +#include "simgear/misc/sg_path.hxx" +#include "simgear/misc/sg_dir.hxx" +#include "simgear/debug/logstream.hxx" +#include "simgear/xml/easyxml.hxx" +#include "simgear/misc/strutils.hxx" +#include "simgear/package/md5.h" + +#ifdef SYSTEM_EXPAT +# include +#else +# include "sg_expat.h" +#endif + +#include "SVNDirectory.hxx" +#include "SVNRepository.hxx" +#include "DAVMultiStatus.hxx" + +using std::cout; +using std::cerr; +using std::endl; +using std::string; + +using namespace simgear; + +#define DAV_NS "DAV::" +#define SVN_NS "svn::" +#define SUBVERSION_DAV_NS "http://subversion.tigris.org/xmlns/dav/" + +namespace { + + #define MAX_ENCODED_INT_LEN 10 + + static size_t + decode_size(unsigned char* &p, + const unsigned char *end) + { + if (p + MAX_ENCODED_INT_LEN < end) + end = p + MAX_ENCODED_INT_LEN; + /* Decode bytes until we're done. */ + size_t result = 0; + + while (p < end) { + result = (result << 7) | (*p & 0x7f); + if (((*p++ >> 7) & 0x1) == 0) { + break; + } + } + + return result; + } + + static bool + try_decode_size(unsigned char* &p, + const unsigned char *end) + { + if (p + MAX_ENCODED_INT_LEN < end) + end = p + MAX_ENCODED_INT_LEN; + + while (p < end) { + if (((*p++ >> 7) & 0x1) == 0) { + return true; + } + } + + return false; + } + +// const char* SVN_UPDATE_REPORT_TAG = SVN_NS "update-report"; + // const char* SVN_TARGET_REVISION_TAG = SVN_NS "target-revision"; + const char* SVN_OPEN_DIRECTORY_TAG = SVN_NS "open-directory"; + const char* SVN_OPEN_FILE_TAG = SVN_NS "open-file"; + const char* SVN_ADD_DIRECTORY_TAG = SVN_NS "add-directory"; + const char* SVN_ADD_FILE_TAG = SVN_NS "add-file"; + const char* SVN_TXDELTA_TAG = SVN_NS "txdelta"; + const char* SVN_SET_PROP_TAG = SVN_NS "set-prop"; + const char* SVN_PROP_TAG = SVN_NS "prop"; + const char* SVN_DELETE_ENTRY_TAG = SVN_NS "delete-entry"; + + const char* SVN_DAV_MD5_CHECKSUM = SUBVERSION_DAV_NS ":md5-checksum"; + + const char* DAV_HREF_TAG = DAV_NS "href"; + const char* DAV_CHECKED_IN_TAG = DAV_NS "checked-in"; + + + const int svn_txdelta_source = 0; + const int svn_txdelta_target = 1; + const int svn_txdelta_new = 2; + + const size_t DELTA_HEADER_SIZE = 4; + + /** + * helper struct to decode and store the SVN delta header + * values + */ + struct SVNDeltaWindow + { + public: + + static bool isWindowComplete(unsigned char* buffer, size_t bytes) + { + unsigned char* p = buffer; + unsigned char* pEnd = p + bytes; + // if we can't decode five sizes, certainly incomplete + for (int i=0; i<5; i++) { + if (!try_decode_size(p, pEnd)) { + return false; + } + } + + p = buffer; + // ignore these three + decode_size(p, pEnd); + decode_size(p, pEnd); + decode_size(p, pEnd); + size_t instructionLen = decode_size(p, pEnd); + size_t newLength = decode_size(p, pEnd); + size_t headerLength = p - buffer; + + return (bytes >= (instructionLen + newLength + headerLength)); + } + + SVNDeltaWindow(unsigned char* p) : + headerLength(0), + _ptr(p) + { + sourceViewOffset = decode_size(p, p+20); + sourceViewLength = decode_size(p, p+20); + targetViewLength = decode_size(p, p+20); + instructionLength = decode_size(p, p+20); + newLength = decode_size(p, p+20); + + headerLength = p - _ptr; + _ptr = p; + } + + bool apply(std::vector& output, std::istream& source) + { + unsigned char* pEnd = _ptr + instructionLength; + unsigned char* newData = pEnd; + + while (_ptr < pEnd) { + int op = ((*_ptr >> 6) & 0x3); + if (op >= 3) { + SG_LOG(SG_IO, SG_INFO, "SVNDeltaWindow: bad opcode:" << op); + return false; + } + + int length = *_ptr++ & 0x3f; + int offset = 0; + + if (length == 0) { + length = decode_size(_ptr, pEnd); + } + + if (length == 0) { + SG_LOG(SG_IO, SG_INFO, "SVNDeltaWindow: malformed stream, 0 length" << op); + return false; + } + + // if op != new, decode another size value + if (op != svn_txdelta_new) { + offset = decode_size(_ptr, pEnd); + } + + if (op == svn_txdelta_target) { + // this is inefficent, but ranges can overlap. + while (length > 0) { + output.push_back(output[offset++]); + --length; + } + } else if (op == svn_txdelta_new) { + output.insert(output.end(), newData, newData + length); + newData += length; + } else if (op == svn_txdelta_source) { + source.seekg(offset); + char* sourceBuf = (char*) malloc(length); + assert(sourceBuf); + source.read(sourceBuf, length); + output.insert(output.end(), sourceBuf, sourceBuf + length); + free(sourceBuf); + } else { + SG_LOG(SG_IO, SG_WARN, "bad opcode logic"); + return false; + } + } // of instruction loop + + return true; + } + + size_t size() const + { + return headerLength + instructionLength + newLength; + } + + unsigned int sourceViewOffset; + size_t sourceViewLength, + targetViewLength; + size_t headerLength, + instructionLength, + newLength; + +private: + unsigned char* _ptr; + }; + + +} // of anonymous namespace + +class SVNReportParser::SVNReportParserPrivate +{ +public: + SVNReportParserPrivate(SVNRepository* repo) : + tree(repo), + status(SVNRepository::SVN_NO_ERROR), + parserInited(false), + currentPath(repo->fsBase()) + { + inFile = false; + currentDir = repo->rootDir(); + } + + ~SVNReportParserPrivate() + { + } + + void startElement (const char * name, const char** attributes) + { + if (status != SVNRepository::SVN_NO_ERROR) { + return; + } + + ExpatAtts attrs(attributes); + tagStack.push_back(name); + if (!strcmp(name, SVN_TXDELTA_TAG)) { + txDeltaData.clear(); + } else if (!strcmp(name, SVN_ADD_FILE_TAG)) { + string fileName(attrs.getValue("name")); + SGPath filePath(currentDir->fsDir().file(fileName)); + currentPath = filePath; + inFile = true; + } else if (!strcmp(name, SVN_OPEN_FILE_TAG)) { + string fileName(attrs.getValue("name")); + SGPath filePath(Dir(currentPath).file(fileName)); + currentPath = filePath; + + if (!filePath.exists()) { + fail(SVNRepository::SVN_ERROR_FILE_NOT_FOUND); + return; + } + + inFile = true; + } else if (!strcmp(name, SVN_ADD_DIRECTORY_TAG)) { + string dirName(attrs.getValue("name")); + Dir d(currentDir->fsDir().file(dirName)); + if (d.exists()) { + // policy decision : if we're doing an add, wipe the existing + d.remove(true); + } + + currentDir = currentDir->addChildDirectory(dirName); + currentPath = currentDir->fsPath(); + currentDir->beginUpdateReport(); + //cout << "addDir:" << currentPath << endl; + } else if (!strcmp(name, SVN_SET_PROP_TAG)) { + setPropName = attrs.getValue("name"); + setPropValue.clear(); + } else if (!strcmp(name, SVN_DAV_MD5_CHECKSUM)) { + md5Sum.clear(); + } else if (!strcmp(name, SVN_OPEN_DIRECTORY_TAG)) { + string dirName; + if (attrs.getValue("name")) { + dirName = string(attrs.getValue("name")); + } + openDirectory(dirName); + } else if (!strcmp(name, SVN_DELETE_ENTRY_TAG)) { + string entryName(attrs.getValue("name")); + deleteEntry(entryName); + } else if (!strcmp(name, DAV_CHECKED_IN_TAG) || + !strcmp(name, DAV_HREF_TAG) || + !strcmp(name, SVN_PROP_TAG)) { + // don't warn on these ones + } else { + //SG_LOG(SG_IO, SG_WARN, "SVNReportParser: unhandled tag:" << name); + } + } // of startElement + + void openDirectory(const std::string& dirName) + { + if (dirName.empty()) { + // root directory, we shall assume + currentDir = tree->rootDir(); + } else { + assert(currentDir); + currentDir = currentDir->child(dirName); + } + + assert(currentDir); + currentPath = currentDir->fsPath(); + currentDir->beginUpdateReport(); + } + + void deleteEntry(const std::string& entryName) + { + currentDir->deleteChildByName(entryName); + } + + bool decodeTextDelta(const SGPath& outputPath) + { + std::vector output, decoded; + strutils::decodeBase64(txDeltaData, decoded); + size_t bytesToDecode = decoded.size(); + + unsigned char* p = decoded.data(); + if (memcmp(p, "SVN\0", DELTA_HEADER_SIZE) != 0) { + return false; // bad header + } + + bytesToDecode -= DELTA_HEADER_SIZE; + p += DELTA_HEADER_SIZE; + std::ifstream source; + source.open(outputPath.c_str(), std::ios::in | std::ios::binary); + + while (bytesToDecode > 0) { + if (!SVNDeltaWindow::isWindowComplete(p, bytesToDecode)) { + SG_LOG(SG_IO, SG_WARN, "SVN txdelta broken window"); + return false; + } + + SVNDeltaWindow window(p); + assert(bytesToDecode >= window.size()); + window.apply(output, source); + bytesToDecode -= window.size(); + p += window.size(); + } + + source.close(); + + std::ofstream f; + f.open(outputPath.c_str(), + std::ios::out | std::ios::trunc | std::ios::binary); + f.write((char*) output.data(), output.size()); + + // compute MD5 while we have the file in memory + memset(&md5Context, 0, sizeof(SG_MD5_CTX)); + SG_MD5Init(&md5Context); + SG_MD5Update(&md5Context, (unsigned char*) output.data(), output.size()); + unsigned char digest[MD5_DIGEST_LENGTH]; + SG_MD5Final(digest, &md5Context); + decodedFileMd5 = strutils::encodeHex(digest, MD5_DIGEST_LENGTH); + + return true; + } + + void endElement (const char * name) + { + if (status != SVNRepository::SVN_NO_ERROR) { + return; + } + + assert(tagStack.back() == name); + tagStack.pop_back(); + + if (!strcmp(name, SVN_TXDELTA_TAG)) { + if (!decodeTextDelta(currentPath)) { + fail(SVNRepository::SVN_ERROR_TXDELTA); + } + } else if (!strcmp(name, SVN_ADD_FILE_TAG)) { + finishFile(currentPath); + } else if (!strcmp(name, SVN_OPEN_FILE_TAG)) { + finishFile(currentPath); + } else if (!strcmp(name, SVN_ADD_DIRECTORY_TAG)) { + // pop directory + currentPath = currentPath.dir(); + currentDir->updateReportComplete(); + currentDir = currentDir->parent(); + } else if (!strcmp(name, SVN_SET_PROP_TAG)) { + if (setPropName == "svn:entry:committed-rev") { + revision = strutils::to_int(setPropValue); + currentVersionName = setPropValue; + if (!inFile) { + // for directories we have the resource already + // for adding files, we might not; we set the version name + // above when ending the add/open-file element + currentDir->collection()->setVersionName(currentVersionName); + } + } + } else if (!strcmp(name, SVN_DAV_MD5_CHECKSUM)) { + // validate against (presumably) just written file + if (decodedFileMd5 != md5Sum) { + fail(SVNRepository::SVN_ERROR_CHECKSUM); + } + } else if (!strcmp(name, SVN_OPEN_DIRECTORY_TAG)) { + currentDir->updateReportComplete(); + if (currentDir->parent()) { + // pop the collection stack + currentDir = currentDir->parent(); + } + + currentPath = currentDir->fsPath(); + } else { + // std::cout << "element:" << name; + } + } + + void finishFile(const SGPath& path) + { + currentPath = path.dir(); + inFile = false; + } + + void data (const char * s, int length) + { + if (status != SVNRepository::SVN_NO_ERROR) { + return; + } + + if (tagStack.back() == SVN_SET_PROP_TAG) { + setPropValue.append(s, length); + } else if (tagStack.back() == SVN_TXDELTA_TAG) { + txDeltaData.append(s, length); + } else if (tagStack.back() == SVN_DAV_MD5_CHECKSUM) { + md5Sum.append(s, length); + } + } + + void pi (const char * target, const char * data) {} + + string tagN(const unsigned int n) const + { + size_t sz = tagStack.size(); + if (n >= sz) { + return string(); + } + + return tagStack[sz - (1 + n)]; + } + + void fail(SVNRepository::ResultCode err) + { + status = err; + } + + SVNRepository* tree; + DAVCollection* rootCollection; + SVNDirectory* currentDir; + SVNRepository::ResultCode status; + + bool parserInited; + XML_Parser xmlParser; + +// in-flight data + string_list tagStack; + string currentVersionName; + string txDeltaData; + SGPath currentPath; + bool inFile; + + unsigned int revision; + SG_MD5_CTX md5Context; + string md5Sum, decodedFileMd5; + std::string setPropName, setPropValue; +}; + + +//////////////////////////////////////////////////////////////////////// +// Static callback functions for Expat. +//////////////////////////////////////////////////////////////////////// + +#define VISITOR static_cast(userData) + +static void +start_element (void * userData, const char * name, const char ** atts) +{ + VISITOR->startElement(name, atts); +} + +static void +end_element (void * userData, const char * name) +{ + VISITOR->endElement(name); +} + +static void +character_data (void * userData, const char * s, int len) +{ + VISITOR->data(s, len); +} + +static void +processing_instruction (void * userData, + const char * target, + const char * data) +{ + VISITOR->pi(target, data); +} + +#undef VISITOR + +/////////////////////////////////////////////////////////////////////////////// + +SVNReportParser::SVNReportParser(SVNRepository* repo) : + _d(new SVNReportParserPrivate(repo)) +{ + +} + +SVNReportParser::~SVNReportParser() +{ +} + +SVNRepository::ResultCode +SVNReportParser::innerParseXML(const char* data, int size) +{ + if (_d->status != SVNRepository::SVN_NO_ERROR) { + return _d->status; + } + + bool isEnd = (data == NULL); + if (!XML_Parse(_d->xmlParser, data, size, isEnd)) { + SG_LOG(SG_IO, SG_INFO, "SVN parse error:" << XML_ErrorString(XML_GetErrorCode(_d->xmlParser)) + << " at line:" << XML_GetCurrentLineNumber(_d->xmlParser) + << " column " << XML_GetCurrentColumnNumber(_d->xmlParser)); + + XML_ParserFree(_d->xmlParser); + _d->parserInited = false; + return SVNRepository::SVN_ERROR_XML; + } else if (isEnd) { + XML_ParserFree(_d->xmlParser); + _d->parserInited = false; + } + + return _d->status; +} + +SVNRepository::ResultCode +SVNReportParser::parseXML(const char* data, int size) +{ + if (_d->status != SVNRepository::SVN_NO_ERROR) { + return _d->status; + } + + if (!_d->parserInited) { + _d->xmlParser = XML_ParserCreateNS(0, ':'); + XML_SetUserData(_d->xmlParser, _d.get()); + XML_SetElementHandler(_d->xmlParser, start_element, end_element); + XML_SetCharacterDataHandler(_d->xmlParser, character_data); + XML_SetProcessingInstructionHandler(_d->xmlParser, processing_instruction); + _d->parserInited = true; + } + + return innerParseXML(data, size); +} + +SVNRepository::ResultCode SVNReportParser::finishParse() +{ + if (_d->status != SVNRepository::SVN_NO_ERROR) { + return _d->status; + } + + return innerParseXML(NULL, 0); +} + +std::string SVNReportParser::etagFromRevision(unsigned int revision) +{ + // etags look like W/"7//", hopefully this is stable + // across different servers and similar + std::ostringstream os; + os << "W/\"" << revision << "//"; + return os.str(); +} + + diff -Nru simgear-2.10.0/simgear/io/SVNReportParser.hxx simgear-3.0.0/simgear/io/SVNReportParser.hxx --- simgear-2.10.0/simgear/io/SVNReportParser.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/SVNReportParser.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,57 @@ +// SVNReportParser -- parser for SVN report XML data +// +// Copyright (C) 2012 James Turner +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +#ifndef SG_IO_SVNREPORTPARSER_HXX +#define SG_IO_SVNREPORTPARSER_HXX + +#include +#include // for auto_ptr + +#include "SVNRepository.hxx" + +class SGPath; + +namespace simgear +{ + +class SVNRepository; + +class SVNReportParser +{ +public: + SVNReportParser(SVNRepository* repo); + ~SVNReportParser(); + + // incremental XML parsing + SVNRepository::ResultCode parseXML(const char* data, int size); + + SVNRepository::ResultCode finishParse(); + + static std::string etagFromRevision(unsigned int revision); + + class SVNReportParserPrivate; +private: + SVNRepository::ResultCode innerParseXML(const char* data, int size); + + std::auto_ptr _d; +}; + +} // of namespace simgear + +#endif // of SG_IO_SVNREPORTPARSER_HXX diff -Nru simgear-2.10.0/simgear/io/SVNRepository.cxx simgear-3.0.0/simgear/io/SVNRepository.cxx --- simgear-2.10.0/simgear/io/SVNRepository.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/SVNRepository.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,382 @@ +// DAVMirrorTree -- mirror a DAV tree to the local file-system +// +// Copyright (C) 2012 James Turner +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include "SVNRepository.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "simgear/debug/logstream.hxx" +#include "simgear/misc/strutils.hxx" +#include +#include +#include +#include +#include +#include + +using std::cout; +using std::cerr; +using std::endl; +using std::string; + +namespace simgear +{ + +typedef std::vector RequestVector; + +class SVNRepoPrivate +{ +public: + SVNRepoPrivate(SVNRepository* parent) : + p(parent), + isUpdating(false), + status(SVNRepository::SVN_NO_ERROR) + { ; } + + SVNRepository* p; // link back to outer + SVNDirectory* rootCollection; + HTTP::Client* http; + std::string baseUrl; + std::string vccUrl; + std::string targetRevision; + bool isUpdating; + SVNRepository::ResultCode status; + + void svnUpdateDone() + { + isUpdating = false; + } + + void updateFailed(HTTP::Request* req, SVNRepository::ResultCode err) + { + SG_LOG(SG_IO, SG_WARN, "SVN: failed to update from:" << req->url() + << "\n(repository:" << p->baseUrl() << ")"); + isUpdating = false; + status = err; + } + + void propFindComplete(HTTP::Request* req, DAVCollection* col); + void propFindFailed(HTTP::Request* req, SVNRepository::ResultCode err); +}; + + +namespace { // anonmouse + + string makeAbsoluteUrl(const string& url, const string& base) + { + if (strutils::starts_with(url, "http://")) + return url; // already absolute + + assert(strutils::starts_with(base, "http://")); + int schemeEnd = base.find("://"); + int hostEnd = base.find('/', schemeEnd + 3); + if (hostEnd < 0) { + return url; + } + + return base.substr(0, hostEnd) + url; + } + + // keep the responses small by only requesting the properties we actually + // care about; the ETag, length and MD5-sum + const char* PROPFIND_REQUEST_BODY = + "" + "" + "" + "" + "" + "" + "" + ""; + + class PropFindRequest : public HTTP::Request + { + public: + PropFindRequest(SVNRepoPrivate* repo) : + Request(repo->baseUrl, "PROPFIND"), + _repo(repo) + { + requestHeader("Depth") = "0"; + setBodyData( PROPFIND_REQUEST_BODY, + "application/xml; charset=\"utf-8\"" ); + } + + protected: + virtual void responseHeadersComplete() + { + if (responseCode() == 207) { + // fine + } else if (responseCode() == 404) { + _repo->propFindFailed(this, SVNRepository::SVN_ERROR_NOT_FOUND); + } else { + SG_LOG(SG_IO, SG_WARN, "request for:" << url() << + " return code " << responseCode()); + _repo->propFindFailed(this, SVNRepository::SVN_ERROR_SOCKET); + _repo = NULL; + } + } + + virtual void onDone() + { + if (responseCode() == 207) { + _davStatus.finishParse(); + if (_davStatus.isValid()) { + _repo->propFindComplete(this, (DAVCollection*) _davStatus.resource()); + } else { + _repo->propFindFailed(this, SVNRepository::SVN_ERROR_SOCKET); + } + } + } + + virtual void gotBodyData(const char* s, int n) + { + if (responseCode() != 207) { + return; + } + _davStatus.parseXML(s, n); + } + + virtual void onFail() + { + HTTP::Request::onFail(); + if (_repo) { + _repo->propFindFailed(this, SVNRepository::SVN_ERROR_SOCKET); + _repo = NULL; + } + } + + private: + SVNRepoPrivate* _repo; + DAVMultiStatus _davStatus; + }; + +class UpdateReportRequest: + public HTTP::Request +{ +public: + UpdateReportRequest(SVNRepoPrivate* repo, + const std::string& aVersionName, + bool startEmpty) : + HTTP::Request("", "REPORT"), + _parser(repo->p), + _repo(repo), + _failed(false) + { + setUrl(repo->vccUrl); + std::string request = + "\n" + "\n" + "" + repo->baseUrl + "\n" + "unknown\n" + "\n"; + + if( !startEmpty ) + { + string_list entries; + _repo->rootCollection->mergeUpdateReportDetails(0, entries); + BOOST_FOREACH(string e, entries) + { + request += e + "\n"; + } + } + + request += ""; + + setBodyData(request, "application/xml; charset=\"utf-8\""); + } + +protected: + virtual void onDone() + { + if (_failed) { + return; + } + + if (responseCode() == 200) { + SVNRepository::ResultCode err = _parser.finishParse(); + if (err) { + _repo->updateFailed(this, err); + _failed = true; + } else { + _repo->svnUpdateDone(); + } + } else if (responseCode() == 404) { + _repo->updateFailed(this, SVNRepository::SVN_ERROR_NOT_FOUND); + _failed = true; + } else { + SG_LOG(SG_IO, SG_WARN, "SVN: request for:" << url() << + " got HTTP status " << responseCode()); + _repo->updateFailed(this, SVNRepository::SVN_ERROR_HTTP); + _failed = true; + } + } + + virtual void gotBodyData(const char* s, int n) + { + if (_failed) { + return; + } + + if (responseCode() != 200) { + return; + } + + SVNRepository::ResultCode err = _parser.parseXML(s, n); + if (err) { + _failed = true; + SG_LOG(SG_IO, SG_WARN, this << ": SVN: request for:" << url() << " failed:" << err); + _repo->updateFailed(this, err); + _repo = NULL; + } + } + + virtual void onFail() + { + HTTP::Request::onFail(); + if (_repo) { + _repo->updateFailed(this, SVNRepository::SVN_ERROR_SOCKET); + _repo = NULL; + } + } +private: + SVNReportParser _parser; + SVNRepoPrivate* _repo; + bool _failed; +}; + +} // anonymous + +SVNRepository::SVNRepository(const SGPath& base, HTTP::Client *cl) : + _d(new SVNRepoPrivate(this)) +{ + _d->http = cl; + _d->rootCollection = new SVNDirectory(this, base); + _d->baseUrl = _d->rootCollection->url(); +} + +SVNRepository::~SVNRepository() +{ + delete _d->rootCollection; +} + +void SVNRepository::setBaseUrl(const std::string &url) +{ + _d->baseUrl = url; + _d->rootCollection->setBaseUrl(url); +} + +std::string SVNRepository::baseUrl() const +{ + return _d->baseUrl; +} + +HTTP::Client* SVNRepository::http() const +{ + return _d->http; +} + +SGPath SVNRepository::fsBase() const +{ + return _d->rootCollection->fsPath(); +} + +bool SVNRepository::isBare() const +{ + if (!fsBase().exists() || Dir(fsBase()).isEmpty()) { + return true; + } + + if (_d->vccUrl.empty()) { + return true; + } + + return false; +} + +void SVNRepository::update() +{ + _d->status = SVN_NO_ERROR; + if (_d->targetRevision.empty() || _d->vccUrl.empty()) { + _d->isUpdating = true; + PropFindRequest* pfr = new PropFindRequest(_d.get()); + http()->makeRequest(pfr); + return; + } + + if (_d->targetRevision == rootDir()->cachedRevision()) { + SG_LOG(SG_IO, SG_DEBUG, baseUrl() << " in sync at version " << _d->targetRevision); + _d->isUpdating = false; + return; + } + + _d->isUpdating = true; + UpdateReportRequest* urr = new UpdateReportRequest(_d.get(), + _d->targetRevision, isBare()); + http()->makeRequest(urr); +} + +bool SVNRepository::isDoingSync() const +{ + if (_d->status != SVN_NO_ERROR) { + return false; + } + + return _d->isUpdating || _d->rootCollection->isDoingSync(); +} + +SVNDirectory* SVNRepository::rootDir() const +{ + return _d->rootCollection; +} + +SVNRepository::ResultCode +SVNRepository::failure() const +{ + return _d->status; +} + +/////////////////////////////////////////////////////////////////////////// + +void SVNRepoPrivate::propFindComplete(HTTP::Request* req, DAVCollection* c) +{ + targetRevision = c->versionName(); + vccUrl = makeAbsoluteUrl(c->versionControlledConfiguration(), baseUrl); + rootCollection->collection()->setVersionControlledConfiguration(vccUrl); + p->update(); +} + +void SVNRepoPrivate::propFindFailed(HTTP::Request *req, SVNRepository::ResultCode err) +{ + if (err != SVNRepository::SVN_ERROR_NOT_FOUND) { + SG_LOG(SG_IO, SG_WARN, "PropFind failed for:" << req->url()); + } + + isUpdating = false; + status = err; +} + +} // of namespace simgear diff -Nru simgear-2.10.0/simgear/io/SVNRepository.hxx simgear-3.0.0/simgear/io/SVNRepository.hxx --- simgear-2.10.0/simgear/io/SVNRepository.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/io/SVNRepository.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,78 @@ +// DAVMirrorTree.hxx - mirror a DAV tree to the local file system +// +// Copyright (C) 2012 James Turner +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +#ifndef SG_IO_DAVMIRRORTREE_HXX +#define SG_IO_DAVMIRRORTREE_HXX + +#include +#include +#include + +#include + +namespace simgear { + + namespace HTTP { + class Client; + } + +class SVNDirectory; +class SVNRepoPrivate; + +class SVNRepository +{ +public: + + SVNRepository(const SGPath& root, HTTP::Client* cl); + ~SVNRepository(); + + SVNDirectory* rootDir() const; + SGPath fsBase() const; + + void setBaseUrl(const std::string& url); + std::string baseUrl() const; + + HTTP::Client* http() const; + + void update(); + + bool isDoingSync() const; + + enum ResultCode { + SVN_NO_ERROR = 0, + SVN_ERROR_NOT_FOUND, + SVN_ERROR_SOCKET, + SVN_ERROR_XML, + SVN_ERROR_TXDELTA, + SVN_ERROR_IO, + SVN_ERROR_CHECKSUM, + SVN_ERROR_FILE_NOT_FOUND, + SVN_ERROR_HTTP + }; + + ResultCode failure() const; +private: + bool isBare() const; + + std::auto_ptr _d; +}; + +} // of namespace simgear + +#endif // of SG_IO_DAVMIRRORTREE_HXX diff -Nru simgear-2.10.0/simgear/io/test_HTTP.cxx simgear-3.0.0/simgear/io/test_HTTP.cxx --- simgear-2.10.0/simgear/io/test_HTTP.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/io/test_HTTP.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -53,48 +53,23 @@ bool complete; bool failed; string bodyData; - string bodyContentType; - + TestRequest(const std::string& url, const std::string method = "GET") : HTTP::Request(url, method), complete(false) { - bodyContentType = "text/plain"; + } - std::map sendHeaders; std::map headers; protected: - string_list requestHeaders() const - { - string_list r; - std::map::const_iterator it; - for (it = sendHeaders.begin(); it != sendHeaders.end(); ++it) { - r.push_back(it->first); - } - return r; - } - - string header(const string& name) const - { - std::map::const_iterator it = sendHeaders.find(name); - if (it == sendHeaders.end()) { - return string(); - } - - return it->second; - } - - virtual void responseHeadersComplete() - { - } - virtual void responseComplete() + virtual void onDone() { complete = true; } - virtual void failure() + virtual void onFail() { failed = true; } @@ -105,11 +80,6 @@ bodyData += string(s, n); } - virtual std::string requestBodyType() const - { - return bodyContentType; - } - virtual void responseHeader(const string& header, const string& value) { headers[header] = value; @@ -405,12 +375,15 @@ class TestServer : public NetChannel { + simgear::NetChannelPoller _poller; public: TestServer() { open(); bind(NULL, 2000); // localhost, any port listen(5); + + _poller.addChannel(this); } virtual ~TestServer() @@ -426,14 +399,25 @@ //cout << "did accept from " << addr.getHost() << ":" << addr.getPort() << endl; TestServerChannel* chan = new TestServerChannel(); chan->setHandle(handle); + + _poller.addChannel(chan); + } + + void poll() + { + _poller.poll(); } }; +TestServer testServer; + void waitForComplete(HTTP::Client* cl, TestRequest* tr) { SGTimeStamp start(SGTimeStamp::now()); while (start.elapsedMSec() < 1000) { cl->update(); + testServer.poll(); + if (tr->complete) { return; } @@ -448,6 +432,8 @@ SGTimeStamp start(SGTimeStamp::now()); while (start.elapsedMSec() < 1000) { cl->update(); + testServer.poll(); + if (tr->failed) { return; } @@ -459,10 +445,11 @@ int main(int argc, char* argv[]) { - TestServer s; HTTP::Client cl; - + // force all requests to use the same connection for this test + cl.setMaxConnections(1); + // test URL parsing TestRequest* tr1 = new TestRequest("http://localhost.woo.zar:2000/test1?foo=bar"); COMPARE(tr1->scheme(), "http"); @@ -518,8 +505,8 @@ { TestRequest* tr = new TestRequest("http://localhost:2000/test_headers"); HTTP::Request_ptr own(tr); - tr->sendHeaders["X-Foo"] = "Bar"; - tr->sendHeaders["X-AnotherHeader"] = "A longer value"; + tr->requestHeader("X-Foo") = "Bar"; + tr->requestHeader("X-AnotherHeader") = "A longer value"; cl.makeRequest(tr); waitForComplete(&cl, tr); @@ -642,6 +629,7 @@ cout << "testing HTTP 1.1 pipelineing" << endl; { + cl.setProxy("", 80); TestRequest* tr = new TestRequest("http://localhost:2000/test1"); HTTP::Request_ptr own(tr); @@ -703,7 +691,7 @@ { cout << "POST" << endl; TestRequest* tr = new TestRequest("http://localhost:2000/test_post?foo=abc&bar=1234&username=johndoe", "POST"); - tr->bodyContentType = "application/x-www-form-urlencoded"; + tr->setBodyData("", "application/x-www-form-urlencoded"); HTTP::Request_ptr own(tr); cl.makeRequest(tr); diff -Nru simgear-2.10.0/simgear/math/CMakeLists.txt simgear-3.0.0/simgear/math/CMakeLists.txt --- simgear-2.10.0/simgear/math/CMakeLists.txt 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/math/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -44,11 +44,13 @@ simgear_component(math math "${SOURCES}" "${HEADERS}") if(ENABLE_TESTS) + add_executable(math_test SGMathTest.cxx) -target_link_libraries(math_test SimGearCore) +target_link_libraries(math_test ${TEST_LIBS}) add_test(math ${EXECUTABLE_OUTPUT_PATH}/math_test) add_executable(geometry_test SGGeometryTest.cxx) -target_link_libraries(geometry_test SimGearCore) +target_link_libraries(geometry_test ${TEST_LIBS}) add_test(geometry ${EXECUTABLE_OUTPUT_PATH}/geometry_test) + endif(ENABLE_TESTS) diff -Nru simgear-2.10.0/simgear/math/interpolater.hxx simgear-3.0.0/simgear/math/interpolater.hxx --- simgear-2.10.0/simgear/math/interpolater.hxx 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/math/interpolater.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -38,9 +38,7 @@ #include #include - #include -using std::string; class SGPropertyNode; @@ -69,7 +67,7 @@ * Constructor. Loads the interpolation table from the specified file. * @param file name of interpolation file */ - SGInterpTable( const string& file ); + SGInterpTable( const std::string& file ); /** diff -Nru simgear-2.10.0/simgear/math/SGMisc.hxx simgear-3.0.0/simgear/math/SGMisc.hxx --- simgear-2.10.0/simgear/math/SGMisc.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/math/SGMisc.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -41,6 +41,39 @@ static T clip(const T& a, const T& _min, const T& _max) { return max(_min, min(_max, a)); } + /** + * Seek a variable towards a target value with given rate and timestep + * + * @param var Variable or eg. SGPropObj + * @param target Target value + * @param rate Max. change rate/sec + * @param dt Time step (sec) + */ + template + static T seek(Var& var, T target, T rate, T dt) + { + if( var < target ) + return var = min(var + rate * dt, target); + else + return var = max(var - rate * dt, target); + } + + /** + * Get @c base raised to the power of @c N + * + * @tparam N Exponent + * @param base Base + */ + template + static T pow(T base) + { + return (N < 0) + ? (1. / pow<-N>(base)) + : ( ((N & 1) ? base : 1) + * ((N > 1) ? pow(base * base) : 1) + ); + } + static int sign(const T& a) { if (a < -SGLimits::min()) diff -Nru simgear-2.10.0/simgear/math/SGRect.hxx simgear-3.0.0/simgear/math/SGRect.hxx --- simgear-2.10.0/simgear/math/SGRect.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/math/SGRect.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -99,11 +99,36 @@ T t() const { return _min.y(); } T b() const { return _max.y(); } + T& l() { return _min.x(); } + T& r() { return _max.x(); } + T& t() { return _min.y(); } + T& b() { return _max.y(); } + void setLeft(T l) { _min.x() = l; } void setRight(T r) { _max.x() = r; } void setTop(T t) { _min.y() = t; } void setBottom(T b) { _max.y() = b; } + /** + * Move rect by vector + */ + SGRect& operator+=(const SGVec2& offset) + { + _min += offset; + _max += offset; + return *this; + } + + /** + * Move rect by vector in inverse direction + */ + SGRect& operator-=(const SGVec2& offset) + { + _min -= offset; + _max -= offset; + return *this; + } + bool contains(T x, T y) const { return _min.x() <= x && x <= _max.x() @@ -121,6 +146,30 @@ _max; }; +template +inline SGRect operator+(SGRect rect, const SGVec2& offset) +{ + return rect += offset; +} + +template +inline SGRect operator+(const SGVec2& offset, SGRect rect) +{ + return rect += offset; +} + +template +inline SGRect operator-(SGRect rect, const SGVec2& offset) +{ + return rect -= offset; +} + +template +inline SGRect operator-(const SGVec2& offset, SGRect rect) +{ + return rect -= offset; +} + template inline std::basic_ostream& diff -Nru simgear-2.10.0/simgear/misc/CMakeLists.txt simgear-3.0.0/simgear/misc/CMakeLists.txt --- simgear-2.10.0/simgear/misc/CMakeLists.txt 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/misc/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -2,8 +2,11 @@ include (SimGearComponent) set(HEADERS + CSSBorder.hxx + ListDiff.hxx ResourceManager.hxx interpolator.hxx + make_new.hxx sg_dir.hxx sg_path.hxx sgstream.hxx @@ -16,7 +19,8 @@ gzcontainerfile.hxx ) -set(SOURCES +set(SOURCES + CSSBorder.cxx ResourceManager.cxx interpolator.cxx sg_dir.cxx @@ -32,15 +36,25 @@ simgear_component(misc misc "${SOURCES}" "${HEADERS}") if(ENABLE_TESTS) + +add_executable(test_CSSBorder CSSBorder_test.cxx) +add_test(CSSBorder ${EXECUTABLE_OUTPUT_PATH}/test_CSSBorder) +target_link_libraries(test_CSSBorder ${TEST_LIBS}) + add_executable(test_tabbed_values tabbed_values_test.cxx) add_test(tabbed_values ${EXECUTABLE_OUTPUT_PATH}/test_tabbed_values) -target_link_libraries(test_tabbed_values SimGearCore) +target_link_libraries(test_tabbed_values ${TEST_LIBS}) add_executable(test_strings strutils_test.cxx ) -add_test(test_strings ${EXECUTABLE_OUTPUT_PATH}/test_strings) -target_link_libraries(test_strings SimGearCore) +add_test(strings ${EXECUTABLE_OUTPUT_PATH}/test_strings) +target_link_libraries(test_strings ${TEST_LIBS}) + +add_executable(test_streams sgstream_test.cxx ) +add_test(streams ${EXECUTABLE_OUTPUT_PATH}/test_streams) +target_link_libraries(test_streams ${TEST_LIBS}) add_executable(test_path path_test.cxx ) -add_test(test_path ${EXECUTABLE_OUTPUT_PATH}/test_path) -target_link_libraries(test_path SimGearCore) +add_test(path ${EXECUTABLE_OUTPUT_PATH}/test_path) +target_link_libraries(test_path ${TEST_LIBS}) + endif(ENABLE_TESTS) diff -Nru simgear-2.10.0/simgear/misc/CSSBorder.cxx simgear-3.0.0/simgear/misc/CSSBorder.cxx --- simgear-2.10.0/simgear/misc/CSSBorder.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/misc/CSSBorder.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,166 @@ +// Parse and represent CSS border definitions (eg. margin, border-image-width) +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "CSSBorder.hxx" + +#include +#include +#include + +namespace simgear +{ + + //---------------------------------------------------------------------------- + bool CSSBorder::isValid() const + { + return valid; + } + + //---------------------------------------------------------------------------- + bool CSSBorder::isNone() const + { + return !valid + || ( offsets.t == 0 + && offsets.r == 0 + && offsets.b == 0 + && offsets.l == 0 ); + } + + //---------------------------------------------------------------------------- + const std::string& CSSBorder::getKeyword() const + { + return keyword; + } + + //---------------------------------------------------------------------------- + CSSBorder::Offsets CSSBorder::getRelOffsets(const SGRect& dim) const + { + Offsets ret = {{0}}; + if( !valid ) + return ret; + + for(int i = 0; i < 4; ++i) + { + ret.val[i] = offsets.val[i]; + if( !types.rel[i] ) + ret.val[i] /= (i & 1) ? dim.width() : dim.height(); + } + + return ret; + } + + //---------------------------------------------------------------------------- + CSSBorder::Offsets CSSBorder::getAbsOffsets(const SGRect& dim) const + { + Offsets ret = {{0}}; + if( !valid ) + return ret; + + for(int i = 0; i < 4; ++i) + { + ret.val[i] = offsets.val[i]; + if( types.rel[i] ) + ret.val[i] *= (i & 1) ? dim.width() : dim.height(); + } + + return ret; + } + + //---------------------------------------------------------------------------- + CSSBorder CSSBorder::parse(const std::string& str) + { + if( str.empty() ) + return CSSBorder(); + + // ['%'?]{1,4} (top[,right[,bottom[,left]]]) + // + // Percentages are relative to the size of the image: the width of the + // image for the horizontal offsets, the height for vertical offsets. + // Numbers represent pixels in the image. + int c = 0; + CSSBorder ret; + + typedef boost::tokenizer > tokenizer; + const boost::char_separator del(" \t\n"); + + tokenizer tokens(str.begin(), str.end(), del); + for( tokenizer::const_iterator tok = tokens.begin(); + tok != tokens.end() && c < 4; + ++tok ) + { + if( isalpha(*tok->begin()) ) + ret.keyword = *tok; + else + { + bool rel = ret.types.rel[c] = (*tok->rbegin() == '%'); + ret.offsets.val[c] = + // Negative values are not allowed and values bigger than the size of + // the image are interpreted as ‘100%’. TODO check max + std::max + ( + 0.f, + boost::lexical_cast + ( + rel ? boost::make_iterator_range(tok->begin(), tok->end() - 1) + : *tok + ) + / + (rel ? 100 : 1) + ); + ++c; + } + } + + // When four values are specified, they set the offsets on the top, right, + // bottom and left sides in that order. + +#define CSS_COPY_VAL(dest, src)\ + {\ + ret.offsets.val[dest] = ret.offsets.val[src];\ + ret.types.rel[dest] = ret.types.rel[src];\ + } + + if( c < 4 ) + { + if( c < 3 ) + { + if( c < 2 ) + // if the right is missing, it is the same as the top. + CSS_COPY_VAL(1, 0); + + // if the bottom is missing, it is the same as the top + CSS_COPY_VAL(2, 0); + } + + // If the left is missing, it is the same as the right + CSS_COPY_VAL(3, 1); + } + +#undef CSS_COPY_VAL + + if( ret.keyword == "none" ) + { + memset(&ret.offsets, 0, sizeof(Offsets)); + ret.keyword.clear(); + } + + ret.valid = true; + return ret; + } + +} // namespace simgear diff -Nru simgear-2.10.0/simgear/misc/CSSBorder.hxx simgear-3.0.0/simgear/misc/CSSBorder.hxx --- simgear-2.10.0/simgear/misc/CSSBorder.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/misc/CSSBorder.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,71 @@ +// Parse and represent CSS border definitions (eg. margin, border-image-width) +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_CSSBORDER_HXX_ +#define SG_CSSBORDER_HXX_ + +#include +#include +#include + +namespace simgear +{ + + class CSSBorder + { + public: + union Offsets + { + float val[4]; + struct { float t, r, b, l; }; + }; + + union OffsetsTypes + { + bool rel[4]; + struct { bool t_rel, r_rel, b_rel, l_rel; }; + }; + + CSSBorder(): + valid(false) + {} + + bool isValid() const; + + /** + * Get whether a non-zero offset exists + */ + bool isNone() const; + + const std::string& getKeyword() const; + + Offsets getRelOffsets(const SGRect& dim) const; + Offsets getAbsOffsets(const SGRect& dim) const; + + static CSSBorder parse(const std::string& str); + + private: + Offsets offsets; + OffsetsTypes types; + std::string keyword; + bool valid; + }; + +} // namespace simgear + +#endif /* SG_CSSBORDER_HXX_ */ diff -Nru simgear-2.10.0/simgear/misc/CSSBorder_test.cxx simgear-3.0.0/simgear/misc/CSSBorder_test.cxx --- simgear-2.10.0/simgear/misc/CSSBorder_test.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/misc/CSSBorder_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,111 @@ +#include + +#include "CSSBorder.hxx" + +#include +#include + +#define COMPARE(a, b) \ + if( std::fabs((a) - (b)) > 1e-4 ) \ + { \ + std::cerr << "line " << __LINE__ << ": failed: "\ + << #a << " != " << #b << " d = " << ((a) - (b)) << std::endl; \ + return 1; \ + } + +#define VERIFY(a) \ + if( !(a) ) \ + { \ + std::cerr << "line " << __LINE__ << ": failed: "\ + << #a << std::endl; \ + return 1; \ + } + +using namespace simgear; + +int main (int ac, char ** av) +{ + CSSBorder b = CSSBorder::parse("5"); + VERIFY(b.isValid()); + VERIFY(!b.isNone()); + CSSBorder::Offsets o = b.getAbsOffsets(SGRect()); + COMPARE(o.t, 5); + COMPARE(o.r, 5); + COMPARE(o.b, 5); + COMPARE(o.l, 5); + + b = CSSBorder::parse("5 10"); + o = b.getAbsOffsets(SGRect()); + COMPARE(o.t, 5); + COMPARE(o.r, 10); + COMPARE(o.b, 5); + COMPARE(o.l, 10); + + b = CSSBorder::parse("5 10 15"); + o = b.getAbsOffsets(SGRect()); + COMPARE(o.t, 5); + COMPARE(o.r, 10); + COMPARE(o.b, 15); + COMPARE(o.l, 10); + + b = CSSBorder::parse("5 10 15 20"); + o = b.getAbsOffsets(SGRect()); + COMPARE(o.t, 5); + COMPARE(o.r, 10); + COMPARE(o.b, 15); + COMPARE(o.l, 20); + + b = CSSBorder::parse("5 10 15 20"); + o = b.getRelOffsets(SGRect(0,0,100,200)); + COMPARE(o.t, 0.025); + COMPARE(o.r, 0.1); + COMPARE(o.b, 0.075); + COMPARE(o.l, 0.2); + + b = CSSBorder::parse("5% 10% 15% 20%"); + o = b.getAbsOffsets(SGRect(0,0,100,200)); + COMPARE(o.t, 10); + COMPARE(o.r, 10); + COMPARE(o.b, 30); + COMPARE(o.l, 20); + + o = b.getRelOffsets(SGRect(0,0,100,200)); + COMPARE(o.t, 0.05); + COMPARE(o.r, 0.1); + COMPARE(o.b, 0.15); + COMPARE(o.l, 0.2); + + b = CSSBorder::parse("5% none"); + o = b.getAbsOffsets(SGRect(0,0,200,200)); + COMPARE(o.t, 0); + COMPARE(o.r, 0); + COMPARE(o.b, 0); + COMPARE(o.l, 0); + VERIFY(b.getKeyword().empty()); + VERIFY(b.isNone()); + + b = CSSBorder::parse("none"); + o = b.getRelOffsets(SGRect(0,0,200,200)); + COMPARE(o.t, 0); + COMPARE(o.r, 0); + COMPARE(o.b, 0); + COMPARE(o.l, 0); + VERIFY(b.getKeyword().empty()); + VERIFY(b.isNone()); + + CSSBorder b2; + VERIFY(!b2.isValid()); + o = b.getAbsOffsets(SGRect(0,0,200,200)); + COMPARE(o.t, 0); + COMPARE(o.r, 0); + COMPARE(o.b, 0); + COMPARE(o.l, 0); + o = b.getRelOffsets(SGRect(0,0,200,200)); + COMPARE(o.t, 0); + COMPARE(o.r, 0); + COMPARE(o.b, 0); + COMPARE(o.l, 0); + + std::cout << "all tests passed successfully!" << std::endl; + return 0; +} diff -Nru simgear-2.10.0/simgear/misc/ListDiff.hxx simgear-3.0.0/simgear/misc/ListDiff.hxx --- simgear-2.10.0/simgear/misc/ListDiff.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/misc/ListDiff.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,85 @@ +///@file +/// Compare lists and get differences +/// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_LISTDIFF_HXX_ +#define SG_LISTDIFF_HXX_ + +#include +#include + +namespace simgear +{ + + template + struct ListDiff + { + typedef std::vector List; + typedef boost::function Callback; + + /** + * Perform list diff in-place (modifies both lists) and call cb_add for + * every element in new_list not in old_list and cb_remove for every element + * in old_list not in new_list. + */ + static void inplace( List& old_list, + List& new_list, + Callback cb_add, + Callback cb_remove ) + { + // Check which elements have been removed. (Removing first and adding + // second should keep the memory usage lower - not for this function, but + // probably for users of this function which use the callbacks to delete + // and create objects) + while( !old_list.empty() ) + { + T& old_el = old_list.front(); + typename List::iterator new_el = + std::find(new_list.begin(), new_list.end(), old_el); + + if( new_el == new_list.end() ) + { + if( cb_remove ) + cb_remove(old_el); + } + else + { + // Element is in both lists -> just ignore + *new_el = new_list.back(); + new_list.pop_back(); + } + + old_list.front() = old_list.back(); + old_list.pop_back(); + } + + // All remaing elements in new_list have not been in old_list, so call + // the add callback for every element if required. + if( cb_add ) + { + for( typename List::iterator it = new_list.begin(); + it != new_list.end(); + ++it ) + cb_add(*it); + } + } + }; + +} // namespace simgear + +#endif /* SG_LISTDIFF_HXX_ */ diff -Nru simgear-2.10.0/simgear/misc/make_new.hxx simgear-3.0.0/simgear/misc/make_new.hxx --- simgear-2.10.0/simgear/misc/make_new.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/misc/make_new.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,52 @@ +// Helper functions which created objects with new. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_MAKE_NEW_HXX_ +#define SG_MAKE_NEW_HXX_ + +namespace simgear +{ + template + T* make_new() + { return new T; } + + template + T* make_new(const A1& a1) + { return new T(a1); } + + template + T* make_new(const A1& a1, const A2& a2) + { return new T(a1, a2); } + + template + Base* make_new_derived() + { return new Derived; } + + template + Base* make_new_derived(const A1& a1) + { return new Derived(a1); } + + template + Base* make_new_derived(const A1& a1, const A2& a2) + { return new Derived(a1, a2); } + + // Add more if needed (Variadic templates would be really nice!) + +} // namespace simgear + +#endif /* SG_MAKE_NEW_HXX_ */ diff -Nru simgear-2.10.0/simgear/misc/path_test.cxx simgear-3.0.0/simgear/misc/path_test.cxx --- simgear-2.10.0/simgear/misc/path_test.cxx 2011-11-14 19:13:02.000000000 +0000 +++ simgear-3.0.0/simgear/misc/path_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -43,6 +43,30 @@ cout << temp.path().modTime() << endl; } +SGPath::Permissions validateNone(const SGPath&) +{ + SGPath::Permissions p; + p.read = false; + p.write = false; + return p; +} + +SGPath::Permissions validateRead(const SGPath&) +{ + SGPath::Permissions p; + p.read = true; + p.write = false; + return p; +} + +SGPath::Permissions validateWrite(const SGPath&) +{ + SGPath::Permissions p; + p.read = false; + p.write = true; + return p; +} + int main(int argc, char* argv[]) { SGPath pa; @@ -143,7 +167,26 @@ COMPARE(pf.dir(), ""); COMPARE(pf.lower_extension(), "gz"); COMPARE(pf.complete_lower_extension(), "txt.gz"); - + + COMPARE(pf.canRead(), true); + COMPARE(pf.canWrite(), true); + + SGPath pp(&validateNone); + COMPARE(pp.canRead(), false); + COMPARE(pp.canWrite(), false); + + pp.append("./test-dir/file.txt"); + COMPARE(pp.create_dir(0700), -3); + + pp.setPermissonChecker(&validateRead); + COMPARE(pp.canRead(), true); + COMPARE(pp.canWrite(), false); + COMPARE(pp.create_dir(0700), -3); + + pp.setPermissonChecker(&validateWrite); + COMPARE(pp.canRead(), false); + COMPARE(pp.canWrite(), true); + test_dir(); cout << "all tests passed OK" << endl; diff -Nru simgear-2.10.0/simgear/misc/sg_dir.cxx simgear-3.0.0/simgear/misc/sg_dir.cxx --- simgear-2.10.0/simgear/misc/sg_dir.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/misc/sg_dir.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -25,6 +25,7 @@ #include #include #include +#include #ifdef _WIN32 # define WIN32_LEAN_AND_MEAN @@ -148,7 +149,11 @@ WIN32_FIND_DATA fData; HANDLE find = FindFirstFile(search.c_str(), &fData); if (find == INVALID_HANDLE_VALUE) { - SG_LOG(SG_GENERAL, SG_WARN, "Dir::children: FindFirstFile failed:" << _path.str()); + int err = GetLastError(); + if (err != ERROR_FILE_NOT_FOUND) { + SG_LOG(SG_GENERAL, SG_WARN, "Dir::children: FindFirstFile failed:" << + _path.str() << " with error:" << err); + } return result; } @@ -255,6 +260,55 @@ return result; } +bool Dir::isEmpty() const +{ + bool empty= true; +#ifdef _WIN32 + WIN32_FIND_DATA fData; + HANDLE find = FindFirstFile("\\*", &fData); + if (find == INVALID_HANDLE_VALUE) { + return true; + } + +// since an empty dir will still have . and .. children, we need +// watch for those - anything else means the dir is really non-empty + bool done = false; + for (; !done; done = (FindNextFile(find, &fData) == 0)) { + if (fData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (!strcmp(fData.cFileName,".") || !strcmp(fData.cFileName,"..")) { + continue; + } + } + + empty = false; + break; + } + + FindClose(find); +#else + DIR* dp = opendir(_path.c_str()); + if (!dp) { + return true; + } + + while (true) { + struct dirent* entry = readdir(dp); + if (!entry) { + break; // done iteration + } + + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { + continue; + } + + empty = false; + break; + } + closedir(dp); +#endif + return empty; +} + bool Dir::exists() const { return _path.isDir(); @@ -298,28 +352,38 @@ return (err == 0); } +bool Dir::removeChildren() const +{ + bool ok; + PathList cs = children(NO_DOT_OR_DOTDOT | INCLUDE_HIDDEN | TYPE_FILE | TYPE_DIR); + BOOST_FOREACH(SGPath path, cs) { + if (path.isDir()) { + Dir childDir(path); + ok = childDir.remove(true); + } else { + ok = path.remove(); + } + + if (!ok) { + SG_LOG(SG_IO, SG_WARN, "failed to remove:" << path); + return false; + } + } // of child iteration + + return true; +} + bool Dir::remove(bool recursive) { if (!exists()) { - SG_LOG(SG_IO, SG_WARN, "attempt to remove non-existant dir:" << _path.str()); + SG_LOG(SG_IO, SG_WARN, "attempt to remove non-existant dir:" << _path); return false; } if (recursive) { - bool ok; - PathList cs = children(NO_DOT_OR_DOTDOT | INCLUDE_HIDDEN | TYPE_FILE | TYPE_DIR); - BOOST_FOREACH(SGPath path, cs) { - if (path.isDir()) { - Dir childDir(path); - ok = childDir.remove(true); - } else { - ok = path.remove(); - } - - if (!ok) { - return false; - } - } // of child iteration + if (!removeChildren()) { + return false; + } } // of recursive deletion #ifdef _WIN32 diff -Nru simgear-2.10.0/simgear/misc/sg_dir.hxx simgear-3.0.0/simgear/misc/sg_dir.hxx --- simgear-2.10.0/simgear/misc/sg_dir.hxx 2011-10-24 11:45:21.000000000 +0000 +++ simgear-3.0.0/simgear/misc/sg_dir.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -72,6 +72,11 @@ PathList children(int types = 0, const std::string& nameGlob = "") const; + /** + * test if the directory contains no children (except '.' and '..') + */ + bool isEmpty() const; + SGPath file(const std::string& name) const; SGPath path() const @@ -91,6 +96,12 @@ bool remove(bool recursive = false); /** + * remove our children but not us + */ + bool removeChildren() const; + + + /** * Check that the directory at the path exists (and is a directory!) */ bool exists() const; diff -Nru simgear-2.10.0/simgear/misc/sg_path.cxx simgear-3.0.0/simgear/misc/sg_path.cxx --- simgear-2.10.0/simgear/misc/sg_path.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/misc/sg_path.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -26,9 +26,11 @@ #include #include +#include #include #include #include +#include #ifdef _WIN32 # include @@ -38,6 +40,7 @@ #include using std::string; +using simgear::strutils::starts_with; /** * define directory path separators @@ -52,6 +55,34 @@ static const char sgSearchPathSep = ':'; #endif +#ifdef _WIN32 + +#include // for CSIDL + +static SGPath pathForCSIDL(int csidl, const SGPath::PermissonChecker& checker) +{ + typedef BOOL (WINAPI*GetSpecialFolderPath)(HWND, LPSTR, int, BOOL); + static GetSpecialFolderPath SHGetSpecialFolderPath = NULL; + + // lazy open+resolve of shell32 + if (!SHGetSpecialFolderPath) { + HINSTANCE shellDll = ::LoadLibrary("shell32"); + SHGetSpecialFolderPath = (GetSpecialFolderPath) GetProcAddress(shellDll, "SHGetSpecialFolderPathA"); + } + + if (!SHGetSpecialFolderPath){ + return SGPath(); + } + + char path[MAX_PATH]; + if (SHGetSpecialFolderPath(0, path, csidl, false)) { + return SGPath(path, checker); + } + + return SGPath(); +} + +#endif // For windows, replace "\" by "/". void @@ -72,27 +103,35 @@ // default constructor -SGPath::SGPath() +SGPath::SGPath(PermissonChecker validator) : path(""), + _permission_checker(validator), _cached(false), + _rwCached(false), _cacheEnabled(true) { } // create a path based on "path" -SGPath::SGPath( const std::string& p ) +SGPath::SGPath( const std::string& p, PermissonChecker validator ) : path(p), + _permission_checker(validator), _cached(false), + _rwCached(false), _cacheEnabled(true) { fix(); } // create a path based on "path" and a "subpath" -SGPath::SGPath( const SGPath& p, const std::string& r ) +SGPath::SGPath( const SGPath& p, + const std::string& r, + PermissonChecker validator ) : path(p.path), + _permission_checker(validator), _cached(false), + _rwCached(false), _cacheEnabled(p._cacheEnabled) { append(r); @@ -101,8 +140,12 @@ SGPath::SGPath(const SGPath& p) : path(p.path), + _permission_checker(p._permission_checker), _cached(p._cached), + _rwCached(p._rwCached), _cacheEnabled(p._cacheEnabled), + _canRead(p._canRead), + _canWrite(p._canWrite), _exists(p._exists), _isDir(p._isDir), _isFile(p._isFile), @@ -113,8 +156,12 @@ SGPath& SGPath::operator=(const SGPath& p) { path = p.path; + _permission_checker = p._permission_checker, _cached = p._cached; + _rwCached = p._rwCached; _cacheEnabled = p._cacheEnabled; + _canRead = p._canRead; + _canWrite = p._canWrite; _exists = p._exists; _isDir = p._isDir; _isFile = p._isFile; @@ -132,16 +179,31 @@ path = p; fix(); _cached = false; + _rwCached = false; } +//------------------------------------------------------------------------------ +void SGPath::setPermissonChecker(PermissonChecker validator) +{ + _permission_checker = validator; + _rwCached = false; +} + +//------------------------------------------------------------------------------ +SGPath::PermissonChecker SGPath::getPermissonChecker() const +{ + return _permission_checker; +} + +//------------------------------------------------------------------------------ void SGPath::set_cached(bool cached) { - _cacheEnabled = cached; + _cacheEnabled = cached; } // append another piece to the existing path void SGPath::append( const string& p ) { - if ( path.size() == 0 ) { + if ( path.empty() ) { path = p; } else { if ( p[0] != sgDirPathSep ) { @@ -151,6 +213,15 @@ } fix(); _cached = false; + _rwCached = false; +} + +//------------------------------------------------------------------------------ +SGPath SGPath::operator/( const std::string& p ) const +{ + SGPath ret = *this; + ret.append(p); + return ret; } //add a new path component to the existing path string @@ -162,13 +233,14 @@ // concatenate a string to the end of the path without inserting a // path separator void SGPath::concat( const string& p ) { - if ( path.size() == 0 ) { + if ( path.empty() ) { path = p; } else { path += p; } fix(); _cached = false; + _rwCached = false; } @@ -267,14 +339,21 @@ if (_cached && _cacheEnabled) { return; } - + + if (path.empty()) { + _exists = false; + return; + } + #ifdef _WIN32 struct _stat buf ; - bool remove_trailing = false; - if ( path.length() > 1 && path[path.length()-1] == '/' ) - remove_trailing=true; - if (_stat (path.substr(0,remove_trailing?path.length()-1:path.length()).c_str(), &buf ) < 0) { + string statPath(path); + if ((path.length() > 1) && (path.back() == '/')) { + statPath.pop_back(); + } + + if (_stat(statPath.c_str(), &buf ) < 0) { _exists = false; } else { _exists = true; @@ -299,12 +378,46 @@ _cached = true; } +void SGPath::checkAccess() const +{ + if( _rwCached && _cacheEnabled ) + return; + + if( _permission_checker ) + { + Permissions p = _permission_checker(*this); + _canRead = p.read; + _canWrite = p.write; + } + else + { + _canRead = true; + _canWrite = true; + } + + _rwCached = true; +} + bool SGPath::exists() const { validate(); return _exists; } +//------------------------------------------------------------------------------ +bool SGPath::canRead() const +{ + checkAccess(); + return _canRead; +} + +//------------------------------------------------------------------------------ +bool SGPath::canWrite() const +{ + checkAccess(); + return _canWrite; +} + bool SGPath::isDir() const { validate(); @@ -333,7 +446,7 @@ bool absolute = !path.empty() && path[0] == sgDirPathSep; unsigned int i = 1; - SGPath dir = absolute ? string( 1, sgDirPathSep ) : ""; + SGPath dir(absolute ? string( 1, sgDirPathSep ) : "", _permission_checker); dir.concat( path_elements[0] ); #ifdef _WIN32 if ( dir.str().find(':') != string::npos && path_elements.size() >= 2 ) { @@ -349,16 +462,26 @@ if ( r == 0 ) { return 0; // Directory already exists } - if ( sgMkDir( dir.c_str(), mode) ) { - SG_LOG( SG_IO, SG_ALERT, "Error creating directory: " + dir.str() ); + for(;;) + { + if( !dir.canWrite() ) + { + SG_LOG( SG_IO, + SG_WARN, "Error creating directory: (" << dir.str() << ")" << + " reason: access denied" ); + return -3; + } + else if( sgMkDir(dir.c_str(), mode) ) + { + SG_LOG( SG_IO, + SG_ALERT, "Error creating directory: (" << dir.str() << ")" ); return -2; - } - for(; i < path_elements.size(); i++) { - dir.append(path_elements[i]); - if ( sgMkDir( dir.c_str(), mode) ) { - SG_LOG( SG_IO, SG_ALERT, "Error creating directory: " + dir.str() ); - return -2; - } + } + + if( i >= path_elements.size() ) + return 0; + + dir.append(path_elements[i++]); } return 0; @@ -367,7 +490,7 @@ string_list sgPathBranchSplit( const string &dirpath ) { string_list path_elements; string element, path = dirpath; - while ( path.size() ) { + while ( ! path.empty() ) { size_t p = path.find( sgDirPathSep ); if ( p != string::npos ) { element = path.substr( 0, p ); @@ -376,7 +499,7 @@ element = path; path = ""; } - if ( element.size() ) + if ( ! element.empty() ) path_elements.push_back( element ); } return path_elements; @@ -425,7 +548,7 @@ bool SGPath::isNull() const { - return path.empty() || (path == ""); + return path.empty(); } std::string SGPath::str_native() const @@ -445,13 +568,27 @@ #endif } +//------------------------------------------------------------------------------ bool SGPath::remove() { - int err = ::unlink(c_str()); - if (err) { - SG_LOG(SG_IO, SG_WARN, "file remove failed: (" << str() << ") " << strerror(errno)); - } - return (err == 0); + if( !canWrite() ) + { + SG_LOG( SG_IO, SG_WARN, "file remove failed: (" << str() << ")" + " reason: access denied" ); + return false; + } + + int err = ::unlink(c_str()); + if( err ) + { + SG_LOG( SG_IO, SG_WARN, "file remove failed: (" << str() << ") " + " reason: " << strerror(errno) ); + // TODO check if failed unlink can really change any of the cached values + } + + _cached = false; // stat again if required + _rwCached = false; + return (err == 0); } time_t SGPath::modTime() const @@ -470,19 +607,148 @@ return (path != other.path); } +//------------------------------------------------------------------------------ bool SGPath::rename(const SGPath& newName) { - if (::rename(c_str(), newName.c_str()) != 0) { - SG_LOG(SG_IO, SG_WARN, "renamed failed: from " << str() << " to " << newName.str() - << " reason: " << strerror(errno)); - return false; - } - - path = newName.path; - _cached = false; - return true; + if( !canRead() || !canWrite() || !newName.canWrite() ) + { + SG_LOG( SG_IO, SG_WARN, "rename failed: from " << str() << + " to " << newName.str() << + " reason: access denied" ); + return false; + } + +#ifdef SG_WINDOWS + if (newName.exists()) { + SGPath r(newName); + if (!r.remove()) { + return false; + } + } +#endif + if( ::rename(c_str(), newName.c_str()) != 0 ) + { + SG_LOG( SG_IO, SG_WARN, "rename failed: from " << str() << + " to " << newName.str() << + " reason: " << strerror(errno) ); + return false; + } + + path = newName.path; + + // Do not remove permission checker (could happen for example if just using + // a std::string as new name) + if( newName._permission_checker ) + _permission_checker = newName._permission_checker; + + _cached = false; + _rwCached = false; + + return true; +} + +//------------------------------------------------------------------------------ +SGPath SGPath::fromEnv(const char* name, const SGPath& def) +{ + const char* val = getenv(name); + if( val && val[0] ) + return SGPath(val, def._permission_checker); + return def; } +#ifdef _WIN32 +//------------------------------------------------------------------------------ +SGPath SGPath::home(const SGPath& def) +{ + // TODO + return def; +} +#else +//------------------------------------------------------------------------------ +SGPath SGPath::home(const SGPath& def) +{ + return fromEnv("HOME", def); +} +#endif + +#ifdef _WIN32 +//------------------------------------------------------------------------------ +SGPath SGPath::desktop(const SGPath& def) +{ + SGPath r = pathForCSIDL(CSIDL_DESKTOPDIRECTORY, def._permission_checker); + if (!r.isNull()) { + return r; + } + + SG_LOG(SG_GENERAL, SG_ALERT, "SGPath::desktop() failed, bad" ); + return def; +} + +SGPath SGPath::documents(const SGPath& def) +{ + SGPath r = pathForCSIDL(CSIDL_MYDOCUMENTS, def._permission_checker); + if (!r.isNull()) { + return r; + } + + SG_LOG(SG_GENERAL, SG_ALERT, "SGPath::documents() failed, bad" ); + return def; +} +#elif __APPLE__ +#include + +//------------------------------------------------------------------------------ +SGPath SGPath::desktop(const SGPath& def) +{ + FSRef ref; + OSErr err = FSFindFolder(kUserDomain, kDesktopFolderType, false, &ref); + if (err) + return def; + + unsigned char path[1024]; + if (FSRefMakePath(&ref, path, 1024) != noErr) + return def; + + return SGPath((const char*) path, def._permission_checker); +} +#else +//------------------------------------------------------------------------------ +SGPath SGPath::desktop(const SGPath& def) +{ + // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + + // $XDG_CONFIG_HOME defines the base directory relative to which user specific + // configuration files should be stored. If $XDG_CONFIG_HOME is either not set + // or empty, a default equal to $HOME/.config should be used. + const SGPath user_dirs = fromEnv("XDG_CONFIG_HOME", home() / ".config") + / "user-dirs.dirs"; + + // Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped + // homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an absolute + // path. No other format is supported. + const std::string DESKTOP = "XDG_DESKTOP_DIR=\""; + + std::ifstream user_dirs_file( user_dirs.c_str() ); + std::string line; + while( std::getline(user_dirs_file, line).good() ) + { + if( !starts_with(line, DESKTOP) || *line.rbegin() != '"' ) + continue; + + // Extract dir from XDG_DESKTOP_DIR="" + line = line.substr(DESKTOP.length(), line.length() - DESKTOP.length() - 1 ); + + const std::string HOME = "$HOME"; + if( starts_with(line, HOME) ) + return home(def) / simgear::strutils::unescape(line.substr(HOME.length())); + + return SGPath(line, def._permission_checker); + } + + return home(def) / "Desktop"; +} +#endif + std::string SGPath::realpath() const { #if (defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED <= 1050) @@ -490,7 +756,7 @@ // This means relative paths cannot be used on Mac OS <= 10.5 return path; #else - #if defined(_MSC_VER) + #if defined(_MSC_VER) /*for MS compilers */ || defined(_WIN32) /*needed for non MS windows compilers like MingW*/ // with absPath NULL, will allocate, and ignore length char *buf = _fullpath( NULL, path.c_str(), _MAX_PATH ); #else diff -Nru simgear-2.10.0/simgear/misc/sg_path.hxx simgear-3.0.0/simgear/misc/sg_path.hxx --- simgear-2.10.0/simgear/misc/sg_path.hxx 2012-01-17 20:33:53.000000000 +0000 +++ simgear-3.0.0/simgear/misc/sg_path.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -52,8 +52,15 @@ public: + struct Permissions + { + bool read : 1; + bool write : 1; + }; + typedef Permissions (*PermissonChecker)(const SGPath&); + /** Default constructor */ - SGPath(); + explicit SGPath(PermissonChecker validator = NULL); /** Copy contructor */ SGPath(const SGPath& p); @@ -64,14 +71,16 @@ * Construct a path based on the starting path provided. * @param p initial path */ - SGPath( const std::string& p ); + SGPath( const std::string& p, PermissonChecker validator = NULL ); /** * Construct a path based on the starting path provided and a relative subpath * @param p initial path * @param r relative subpath */ - SGPath( const SGPath& p, const std::string& r ); + SGPath( const SGPath& p, + const std::string& r, + PermissonChecker validator = NULL ); /** Destructor */ ~SGPath(); @@ -85,7 +94,10 @@ bool operator==(const SGPath& other) const; bool operator!=(const SGPath& other) const; - + + void setPermissonChecker(PermissonChecker validator); + PermissonChecker getPermissonChecker() const; + /** * Set if file information (exists, type, mod-time) is cached or * retrieved each time it is queried. Caching is enabled by default @@ -99,6 +111,13 @@ void append( const std::string& p ); /** + * Get a copy of this path with another piece appended. + * + * @param p additional path component + */ + SGPath operator/( const std::string& p ) const; + + /** * Append a new piece to the existing path. Inserts a search path * separator to the existing path and the new patch component. * @param p additional path component */ @@ -191,6 +210,17 @@ */ int create_dir(mode_t mode); + /** + * Check if reading file is allowed. Readabilty does not imply the existance + * of the file. + * + * @note By default all files will be marked as readable. No check is made + * if the operating system allows the given file to be read. Derived + * classes may actually implement custom read/write rights. + */ + bool canRead() const; + bool canWrite() const; + bool isFile() const; bool isDir() const; @@ -226,16 +256,45 @@ * or if the destination already exists, or is not writeable */ bool rename(const SGPath& newName); + + /** + * Get a path stored in the environment variable with the given \a name. + * + * @param name Name of the environment variable + * @param def Default path to return if the environment variable does not + * exist or is empty. + */ + static SGPath fromEnv(const char* name, const SGPath& def = SGPath()); + + /** + * Get path to user's home directory + */ + static SGPath home(const SGPath& def = SGPath()); + + /** + * Get path to the user's desktop directory + */ + static SGPath desktop(const SGPath& def = SGPath()); + + /** + * Get path to the user's documents directory + */ + static SGPath documents(const SGPath& def = SGPath()); private: void fix(); void validate() const; + void checkAccess() const; std::string path; - + PermissonChecker _permission_checker; + mutable bool _cached : 1; + mutable bool _rwCached : 1; bool _cacheEnabled : 1; ///< cacheing can be disbled if required + mutable bool _canRead : 1; + mutable bool _canWrite : 1; mutable bool _exists : 1; mutable bool _isDir : 1; mutable bool _isFile : 1; diff -Nru simgear-2.10.0/simgear/misc/sgstream.cxx simgear-3.0.0/simgear/misc/sgstream.cxx --- simgear-2.10.0/simgear/misc/sgstream.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/misc/sgstream.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -102,14 +102,17 @@ skipeol( istream& in ) { char c = '\0'; - // skip to end of line. + // make sure we detect LF, CR and CR/LF while ( in.get(c) ) { - if ( (c == '\n') || (c == '\r') ) { - break; - } + if (c == '\n') + break; + else if (c == '\r') { + if (in.peek() == '\n') + in.get(c); + break; + } } - return in; } diff -Nru simgear-2.10.0/simgear/misc/sgstream_test.cxx simgear-3.0.0/simgear/misc/sgstream_test.cxx --- simgear-2.10.0/simgear/misc/sgstream_test.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/misc/sgstream_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,51 @@ +#include +#include + +#include // for EXIT_FAILURE + +using std::ofstream; +using std::cout; +using std::endl; + +#include + +int main() +{ + const char* fileName = "testfile"; + { + ofstream f; + f.open(fileName, std::ios::binary | std::ios::trunc | std::ios::out); + f.write("first line ends with line-feed\n" + "second line ends with just a cr\r" + "third line ends with both\r\n" + "fourth line as well\r\n" + "fifth line is another CR/LF line\r\n" + "end of test\r\n", 1024); + f.close(); + } + + sg_gzifstream sg(fileName); + std::string stuff; + sg >> skipeol; + sg >> stuff; + if (stuff != "second") return EXIT_FAILURE; + cout << "Detection of LF works." << endl; + + sg >> skipeol; + sg >> stuff; + if (stuff != "third") return EXIT_FAILURE; + cout << "Detection of CR works." << endl; + + sg >> skipeol; + sg >> stuff; + if (stuff != "fourth") return EXIT_FAILURE; + cout << "Detection of CR/LF works." << endl; + + sg >> skipeol; + sg >> skipeol; + sg >> stuff; + if (stuff != "end") return EXIT_FAILURE; + cout << "Detection of 2 following CR/LF lines works." << endl; + + return EXIT_SUCCESS; +} diff -Nru simgear-2.10.0/simgear/misc/strutils.cxx simgear-3.0.0/simgear/misc/strutils.cxx --- simgear-2.10.0/simgear/misc/strutils.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/misc/strutils.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -26,6 +26,8 @@ #include "strutils.hxx" +#include + using std::string; using std::vector; using std::stringstream; @@ -33,6 +35,39 @@ namespace simgear { namespace strutils { + /* + * utf8ToLatin1() convert utf8 to latin, useful for accent character (i.e éâàîè...) + */ + template size_t get_length (Iterator p) { + unsigned char c = static_cast (*p); + if (c < 0x80) return 1; + else if (!(c & 0x20)) return 2; + else if (!(c & 0x10)) return 3; + else if (!(c & 0x08)) return 4; + else if (!(c & 0x04)) return 5; + else return 6; + } + + typedef unsigned int value_type; + template value_type get_value (Iterator p) { + size_t len = get_length (p); + if (len == 1) return *p; + value_type res = static_cast ( *p & (0xff >> (len + 1))) << ((len - 1) * 6 ); + for (--len; len; --len) + res |= (static_cast (*(++p)) - 0x80) << ((len - 1) * 6); + return res; + } + + string utf8ToLatin1( string& s_utf8 ) { + string s_latin1; + for (string::iterator p = s_utf8.begin(); p != s_utf8.end(); ++p) { + value_type value = get_value(p); + if (value > 0xff) SG_LOG(SG_IO, SG_WARN, "utf8ToLatin1: wrong char value: " << value); + s_latin1 += static_cast(value); + } + return s_latin1; + } + /** * */ @@ -204,15 +239,18 @@ bool starts_with( const string & s, const string & substr ) - { - return s.find( substr ) == 0; + { + return s.compare(0, substr.length(), substr) == 0; } bool ends_with( const string & s, const string & substr ) - { - size_t n = s.rfind( substr ); - return (n != string::npos) && (n == s.length() - substr.length()); + { + if( substr.length() > s.length() ) + return false; + return s.compare( s.length() - substr.length(), + substr.length(), + substr ) == 0; } string simplify(const string& s) @@ -300,6 +338,239 @@ return rslt; } - } // end namespace strutils + string lowercase(const string &s) { + string rslt(s); + for(string::iterator p = rslt.begin(); p != rslt.end(); p++){ + *p = tolower(*p); + } + return rslt; + } + + void lowercase(string &s) { + for(string::iterator p = s.begin(); p != s.end(); p++){ + *p = tolower(*p); + } + } + +#if defined(SG_WINDOWS) + +#include + +static WCharVec convertMultiByteToWString(DWORD encoding, const std::string& a) +{ + WCharVec result; + DWORD flags = 0; + int requiredWideChars = MultiByteToWideChar(encoding, flags, + a.c_str(), a.size(), + NULL, 0); + result.resize(requiredWideChars); + MultiByteToWideChar(encoding, flags, a.c_str(), a.size(), + result.data(), result.size()); + return result; +} + +WCharVec convertUtf8ToWString(const std::string& a) +{ + return convertMultiByteToWString(CP_UTF8, a); +} + +#endif + +std::string convertWindowsLocal8BitToUtf8(const std::string& a) +{ +#ifdef SG_WINDOWS + DWORD flags = 0; + WCharVec wideString = convertMultiByteToWString(CP_ACP, a); + + // convert down to UTF-8 + std::vector result; + int requiredUTF8Chars = WideCharToMultiByte(CP_UTF8, flags, + wideString.data(), wideString.size(), + NULL, 0, NULL, NULL); + result.resize(requiredUTF8Chars); + WideCharToMultiByte(CP_UTF8, flags, + wideString.data(), wideString.size(), + result.data(), result.size(), NULL, NULL); + return std::string(result.data(), result.size()); +#else + return a; +#endif +} + + + +static const std::string base64_chars = +"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +"abcdefghijklmnopqrstuvwxyz" +"0123456789+/"; + +static const unsigned char base64_decode_map[128] = +{ + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, + 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 127, 127, 127, 127, 127 +}; + + +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +static bool is_whitespace(unsigned char c) { + return ((c == ' ') || (c == '\r') || (c == '\n')); +} + +void decodeBase64(const std::string& encoded_string, std::vector& ret) +{ + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + + while (in_len-- && ( encoded_string[in_] != '=')) { + if (is_whitespace( encoded_string[in_])) { + in_++; + continue; + } + + if (!is_base64(encoded_string[in_])) { + break; + } + + char_array_4[i++] = encoded_string[in_]; in_++; + if (i ==4) { + for (i = 0; i <4; i++) + char_array_4[i] = base64_decode_map[char_array_4[i]]; + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret.push_back(char_array_3[i]); + i = 0; + } + } + + if (i) { + for (j = i; j <4; j++) + char_array_4[j] = 0; + + for (j = 0; j <4; j++) + char_array_4[j] = base64_decode_map[char_array_4[j]]; + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret.push_back(char_array_3[j]); + } +} + +const char hexChar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + +std::string encodeHex(const std::string& bytes) +{ + std::string hex; + size_t count = bytes.size(); + for (unsigned int i=0; i> 4]); + hex.push_back(hexChar[c & 0x0f]); + } + + return hex; +} + +std::string encodeHex(const unsigned char* rawBytes, unsigned int length) +{ + std::string hex; + for (unsigned int i=0; i> 4]); + hex.push_back(hexChar[c & 0x0f]); + } + + return hex; +} + +//------------------------------------------------------------------------------ +std::string unescape(const char* s) +{ + std::string r; + while( *s ) + { + if( *s != '\\' ) + { + r += *s++; + continue; + } + + if( !*++s ) + break; + + if (*s == '\\') { + r += '\\'; + } else if (*s == 'n') { + r += '\n'; + } else if (*s == 'r') { + r += '\r'; + } else if (*s == 't') { + r += '\t'; + } else if (*s == 'v') { + r += '\v'; + } else if (*s == 'f') { + r += '\f'; + } else if (*s == 'a') { + r += '\a'; + } else if (*s == 'b') { + r += '\b'; + } else if (*s == 'x') { + if (!*++s) + break; + int v = 0; + for (int i = 0; i < 2 && isxdigit(*s); i++, s++) + v = v * 16 + (isdigit(*s) ? *s - '0' : 10 + tolower(*s) - 'a'); + r += v; + continue; + + } else if (*s >= '0' && *s <= '7') { + int v = *s++ - '0'; + for (int i = 0; i < 3 && *s >= '0' && *s <= '7'; i++, s++) + v = v * 8 + *s - '0'; + r += v; + continue; + + } else { + r += *s; + } + s++; + } + return r; +} + +string sanitizePrintfFormat(const string& input) +{ + string::size_type i = input.find("%n"); + if (i != string::npos) { + SG_LOG(SG_IO, SG_WARN, "sanitizePrintfFormat: bad format string:" << input); + return string(); + } + + return input; +} + +} // end namespace strutils } // end namespace simgear diff -Nru simgear-2.10.0/simgear/misc/strutils.hxx simgear-3.0.0/simgear/misc/strutils.hxx --- simgear-2.10.0/simgear/misc/strutils.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/misc/strutils.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -38,6 +38,11 @@ namespace simgear { namespace strutils { + /** + * utf8ToLatin1() convert utf8 to latin, useful for accent character (i.e éâàîè...) + */ + std::string utf8ToLatin1( std::string & s_utf8 ); + // /** // * atof() wrapper for "string" type // */ @@ -137,7 +142,7 @@ /** * Like strcmp(), but for dotted versions strings NN.NN.NN - * any number of terms are support. + * any number of terms are supported. * @return 0 if versions match, -ve number if v1 is lower, +ve if v1 * is greater */ @@ -149,6 +154,61 @@ */ std::string uppercase(const std::string &s); + /** + * Convert a string to lower case. + * @return lower case string + */ + std::string lowercase(const std::string &s); + + /** + * Convert a string to lower case in place + */ + void lowercase(std::string &s); + + /** + * convert a string in the local Windows 8-bit encoding to UTF-8 + * (no-op on other platforms) + */ + std::string convertWindowsLocal8BitToUtf8(const std::string& a); + +#if defined(SG_WINDOWS) + typedef std::vector WCharVec; + WCharVec convertUtf8ToWString(const std::string& a); +#endif + + /** + * convert base-64 encoded data to raw bytes (possibly with embedded + * NULs). Throws an exception if input data is not base64, or is + * malformed + */ + void decodeBase64(const std::string& a, std::vector& output); + + /** + * convert bytes to hexadecimal equivalent + */ + std::string encodeHex(const std::string& bytes); + + std::string encodeHex(const unsigned char* rawBytes, unsigned int length); + + /** + * Unescape string. + * + * @param str String possibly containing escaped characters. + * @return string with escaped characters replaced by single character + * values. + */ + std::string unescape(const char* str); + + inline std::string unescape(const std::string& str) + { return unescape(str.c_str()); } + + /** + * Check a printf-style format string for dangerous (buffer-overflowing, + * memory re-writing) format tokens. If a problematic token is + * found, logs an error (SG_WARN) and returns an empty format string. + */ + std::string sanitizePrintfFormat(const std::string& input); + } // end namespace strutils } // end namespace simgear diff -Nru simgear-2.10.0/simgear/misc/strutils_test.cxx simgear-3.0.0/simgear/misc/strutils_test.cxx --- simgear-2.10.0/simgear/misc/strutils_test.cxx 2011-10-24 11:45:21.000000000 +0000 +++ simgear-3.0.0/simgear/misc/strutils_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -76,7 +76,9 @@ std::string j = join(la, "&"); COMPARE(j, "zero&one&two&three&four&five"); - + + COMPARE(unescape("\\ \\n\\t\\x41\\117a"), " \n\tAOa"); + cout << "all tests passed successfully!" << endl; return 0; } diff -Nru simgear-2.10.0/simgear/misc/tabbed_values.cxx simgear-3.0.0/simgear/misc/tabbed_values.cxx --- simgear-2.10.0/simgear/misc/tabbed_values.cxx 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/misc/tabbed_values.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -26,8 +26,7 @@ #include "tabbed_values.hxx" -SGTabbedValues::SGTabbedValues(const char *line) : - _line(line) +SGTabbedValues::SGTabbedValues(const char *line) { assert(line); _fields.push_back(const_cast(line)); diff -Nru simgear-2.10.0/simgear/misc/tabbed_values.hxx simgear-3.0.0/simgear/misc/tabbed_values.hxx --- simgear-2.10.0/simgear/misc/tabbed_values.hxx 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/misc/tabbed_values.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -45,8 +45,6 @@ long getLongAt(const unsigned int) const; private: const char* fieldAt(const unsigned int offset) const; - - const char* _line; /** this is first character of each field, if the field is empty it will be the tab character. It is lazily built as needed, so diff -Nru simgear-2.10.0/simgear/misc/test_macros.hxx simgear-3.0.0/simgear/misc/test_macros.hxx --- simgear-2.10.0/simgear/misc/test_macros.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/misc/test_macros.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,19 @@ + +#ifndef SG_MISC_TEST_MACROS_HXX +#define SG_MISC_TEST_MACROS_HXX + +#define COMPARE(a, b) \ + if ((a) != (b)) { \ + std::cerr << "failed:" << #a << " != " << #b << std::endl; \ + std::cerr << "\tgot:'" << a << "'" << std::endl; \ + exit(1); \ + } + +#define VERIFY(a) \ + if (!(a)) { \ + std::cerr << "failed:" << #a << std::endl; \ + exit(1); \ + } + + +#endif // of SG_MISC_TEST_MACROS_HXX diff -Nru simgear-2.10.0/simgear/nasal/code.c simgear-3.0.0/simgear/nasal/code.c --- simgear-2.10.0/simgear/nasal/code.c 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/code.c 2014-02-15 00:04:11.000000000 +0000 @@ -180,6 +180,8 @@ globals->symbols = naNewHash(c); globals->save = naNewVector(c); + globals->save_hash = naNewHash(c); + globals->next_gc_key = 0; // Cache pre-calculated "me", "arg" and "parents" scalars globals->meRef = naInternSymbol(naStr_fromdata(naNewString(c), "me", 2)); @@ -313,7 +315,10 @@ ctx->opFrame = opf; if(IS_CCODE(code)) { - naRef result = (*PTR(code).ccode->fptr)(ctx, obj, nargs, args); + struct naCCode *ccode = PTR(code).ccode; + naRef result = ccode->fptru + ? (*ccode->fptru)(ctx, obj, nargs, args, ccode->user_data) + : (*ccode->fptr)(ctx, obj, nargs, args); if(named) ERR(ctx, "native functions have no named arguments"); ctx->opTop = ctx->opFrame; PUSH(result); @@ -441,14 +446,17 @@ naRef p; struct VecRec* pv; if(--count < 0) return "too many parents"; - if(!IS_HASH(obj) && !IS_GHOST(obj)) return "non-objects have no members"; - + if (IS_GHOST(obj)) { if (ghostGetMember(ctx, obj, field, out)) return ""; if(!ghostGetMember(ctx, obj, globals->parentsRef, &p)) return 0; - } else { + } else if (IS_HASH(obj)) { if(naHash_get(obj, field, out)) return ""; if(!naHash_get(obj, globals->parentsRef, &p)) return 0; + } else if (IS_STR(obj) ) { + return getMember_r(ctx, getStringMethods(ctx), field, out, count); + } else { + return "non-objects have no members"; } if(!IS_VEC(p)) return "object \"parents\" field not vector"; @@ -759,6 +767,27 @@ naVec_append(globals->save, obj); } +int naGCSave(naRef obj) +{ + int key = globals->next_gc_key++; + naHash_set(globals->save_hash, naNum(key), obj); + return key; +} + +void naGCRelease(int key) +{ + naHash_delete(globals->save_hash, naNum(key)); +} + +void naClearSaved() +{ + naContext c; + c = naNewContext(); + globals->save = naNewVector(c); + globals->save_hash = naNewHash(c); + naFreeContext(c); +} + int naStackDepth(naContext ctx) { return ctx ? ctx->fTop + naStackDepth(ctx->callChild): 0; @@ -845,8 +874,10 @@ } if(IS_CCODE(PTR(func).func->code)) { - naCFunction fp = PTR(PTR(func).func->code).ccode->fptr; - result = (*fp)(ctx, obj, argc, args); + struct naCCode *ccode = PTR(PTR(func).func->code).ccode; + result = ccode->fptru + ? (*ccode->fptru)(ctx, obj, argc, args, ccode->user_data) + : (*ccode->fptr) (ctx, obj, argc, args); if(!ctx->callParent) naModUnlock(); return result; } @@ -907,3 +938,52 @@ if(!ctx->callParent) naModUnlock(); return result; } + +static void logError(naContext ctx) +{ + int i, stack_depth = naStackDepth(ctx); + printf("Nasal runtime error: %s\n", naGetError(ctx)); + if( stack_depth < 1 ) + return; + printf(" at %s\n", naStr_data(naGetSourceFile(ctx, 0))); + printf(", line %d\n", naGetLine(ctx, 0)); + for(i = 1; i < stack_depth; ++i ) + printf( " called from: %s, line %d", + naStr_data(naGetSourceFile(ctx, i)), + naGetLine(ctx, i)); +} + +static naErrorHandler error_handler = &logError; +naErrorHandler naSetErrorHandler(naErrorHandler cb) +{ + naErrorHandler old_handler = error_handler; + error_handler = cb; + return old_handler; +} + +static int call_count = 0; +naRef naCallMethodCtx( naContext ctx, + naRef code, + naRef self, + int argc, + naRef* args, + naRef locals ) +{ + naRef result; + if(call_count) naModUnlock(); + call_count++; + result = naCall(ctx, code, argc, args, self, locals); + if(naGetError(ctx) && error_handler) + error_handler(ctx); + call_count--; + if(call_count) naModLock(); + return result; +} + +naRef naCallMethod(naRef code, naRef self, int argc, naRef* args, naRef locals) +{ + naContext ctx = naNewContext(); + naRef result = naCallMethodCtx(ctx, code, self, argc, args, locals); + naFreeContext(ctx); + return result; +} diff -Nru simgear-2.10.0/simgear/nasal/codegen.c simgear-3.0.0/simgear/nasal/codegen.c --- simgear-2.10.0/simgear/nasal/codegen.c 2011-11-14 19:13:02.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/codegen.c 2014-02-15 00:04:11.000000000 +0000 @@ -147,7 +147,15 @@ static int defArg(struct Parser* p, struct Token* t) { - if(t->type == TOK_LPAR) return defArg(p, RIGHT(t)); + if(t->type == TOK_LPAR) { + // http://code.google.com/p/flightgear-bugs/issues/detail?id=737 + // TOK_LPAR can mean multi-value assignment or function call, + // disambigaute by checking the rule of the token + if (t->rule == PREC_SUFFIX) + naParseError(p, "default arguments cannot be function calls", t->line); + return defArg(p, RIGHT(t)); + } + if(t->type == TOK_MINUS && RIGHT(t) && RIGHT(t)->type == TOK_LITERAL && !RIGHT(t)->str) { @@ -477,6 +485,11 @@ static void genBreakContinue(struct Parser* p, struct Token* t) { int levels = 1, loop = -1, bp, cp, i; + // http://code.google.com/p/flightgear-bugs/issues/detail?id=587 + // Make sure we are inside of a loop + if(p->cg->loopTop <= 0) + naParseError(p, "break/continue outside of a valid loop", t->line); + if(RIGHT(t)) { if(RIGHT(t)->type != TOK_SYMBOL) naParseError(p, "bad break/continue label", t->line); @@ -542,7 +555,10 @@ if(parListLen(lv) || (lv->type == TOK_VAR && parListLen(RIGHT(lv)))) { if(lv->type == TOK_VAR) { lv = RIGHT(lv); var = 1; } len = parListLen(lv); - if(rv->type == TOK_LPAR) { + // http://code.google.com/p/flightgear-bugs/issues/detail?id=585 + // TOK_LPAR can mean multi-value assignment or function call, + // disambigaute by checking the rule of the token + if(rv->type == TOK_LPAR && rv->rule != PREC_SUFFIX) { if(len != parListLen(rv)) naParseError(p, "bad assignment count", rv->line); genCommaList(p, LEFT(rv)); diff -Nru simgear-2.10.0/simgear/nasal/code.h simgear-3.0.0/simgear/nasal/code.h --- simgear-2.10.0/simgear/nasal/code.h 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/code.h 2014-02-15 00:04:11.000000000 +0000 @@ -62,7 +62,11 @@ // A hash of symbol names naRef symbols; + // Vector/hash containing objects which should not be freed by the gc + // TODO do we need a separate vector and hash? naRef save; + naRef save_hash; + int next_gc_key; struct Context* freeContexts; struct Context* allContexts; diff -Nru simgear-2.10.0/simgear/nasal/cppbind/CMakeLists.txt simgear-3.0.0/simgear/nasal/cppbind/CMakeLists.txt --- simgear-2.10.0/simgear/nasal/cppbind/CMakeLists.txt 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -2,23 +2,35 @@ set(HEADERS Ghost.hxx + NasalCallContext.hxx NasalHash.hxx - from_nasal_detail.hxx + NasalObjectHolder.hxx + NasalString.hxx from_nasal.hxx - nasal_traits.hxx to_nasal.hxx ) +set(DETAIL_HEADERS + detail/from_nasal_function_templates.hxx + detail/from_nasal_helper.hxx + detail/functor_templates.hxx + detail/nasal_traits.hxx + detail/to_nasal_helper.hxx +) + set(SOURCES NasalHash.cxx - from_nasal.cxx - to_nasal.cxx + NasalObjectHolder.cxx + NasalString.cxx + detail/from_nasal_helper.cxx + detail/to_nasal_helper.cxx ) simgear_component(nasal/cppbind nasal/cppbind "${SOURCES}" "${HEADERS}") +simgear_component(nasal/cppbind/detail nasal/cppbind/detail "" "${DETAIL_HEADERS}") if(ENABLE_TESTS) add_executable(test_cppbind cppbind_test.cxx) - add_test(test_cppbind ${EXECUTABLE_OUTPUT_PATH}/test_cppbind) - target_link_libraries(test_cppbind SimGearCore) + add_test(cppbind ${EXECUTABLE_OUTPUT_PATH}/test_cppbind) + target_link_libraries(test_cppbind ${TEST_LIBS}) endif(ENABLE_TESTS) \ No newline at end of file diff -Nru simgear-2.10.0/simgear/nasal/cppbind/cppbind_test.cxx simgear-3.0.0/simgear/nasal/cppbind/cppbind_test.cxx --- simgear-2.10.0/simgear/nasal/cppbind/cppbind_test.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/cppbind_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -2,8 +2,11 @@ #include "Ghost.hxx" #include "NasalHash.hxx" +#include "NasalString.hxx" +#include #include +#include #include #include @@ -15,6 +18,12 @@ return 1; \ } +enum MyEnum +{ + ENUM_FIRST, + ENUM_ANOTHER, + ENUM_LAST +}; struct Base { naRef member(const nasal::CallContext&) { return naNil(); } @@ -22,7 +31,21 @@ std::string getString() const { return ""; } void setString(const std::string&) {} + void constVoidFunc() const {} + size_t test1Arg(const std::string& str) const { return str.length(); } + bool test2Args(const std::string& s, bool c) { return c && s.empty(); } + + std::string var; + const std::string& getVar() const { return var; } + void setVar(const std::string v) { var = v; } }; + +void baseVoidFunc(Base& b) {} +void baseConstVoidFunc(const Base& b) {} +size_t baseFunc2Args(Base& b, int x, const std::string& s) { return x + s.size(); } +std::string testPtr(Base& b) { return b.getString(); } +void baseFuncCallContext(const Base&, const nasal::CallContext&) {} + struct Derived: public Base { @@ -35,22 +58,37 @@ { }; + +typedef boost::shared_ptr BasePtr; +typedef std::vector BaseVec; + struct DoubleDerived2: public Derived { + const BasePtr& getBase() const{return _base;} + BasePtr _base; + BaseVec doSomeBaseWork(const BaseVec& v) { return v; } +}; + +class SGReferenceBasedClass: + public SGReferenced +{ }; -typedef boost::shared_ptr BasePtr; typedef boost::shared_ptr DerivedPtr; typedef boost::shared_ptr DoubleDerivedPtr; typedef boost::shared_ptr DoubleDerived2Ptr; +typedef SGSharedPtr SGRefBasedPtr; -naRef member(Derived&, const nasal::CallContext&) { return naNil(); } +typedef boost::weak_ptr DerivedWeakPtr; + +naRef derivedFreeMember(Derived&, const nasal::CallContext&) { return naNil(); } naRef f_derivedGetX(naContext c, const Derived& d) { return nasal::to_nasal(c, d.getX()); } +naRef f_freeFunction(nasal::CallContext c) { return c.requireArg(0); } int main(int argc, char* argv[]) { @@ -59,6 +97,9 @@ using namespace nasal; + r = to_nasal(c, ENUM_ANOTHER); + VERIFY( from_nasal(c, r) == ENUM_ANOTHER ); + r = to_nasal(c, "Test"); VERIFY( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 ); VERIFY( from_nasal(c, r) == "Test" ); @@ -101,6 +142,7 @@ hash.set("vec2", vec); hash.set("name", "my-name"); hash.set("string", std::string("blub")); + hash.set("func", &f_freeFunction); r = to_nasal(c, hash); VERIFY( naIsHash(r) ); @@ -111,45 +153,116 @@ Hash mod = hash.createHash("mod"); mod.set("parent", hash); + + // 'func' is a C++ function registered to Nasal and now converted back to C++ + boost::function f = hash.get("func"); + VERIFY( f ); + VERIFY( f(3) == 3 ); + + boost::function fs = hash.get("func"); + VERIFY( fs ); + VERIFY( fs(14) == "14" ); + + typedef boost::function FuncVoidInt; + FuncVoidInt fvi = hash.get("func"); + VERIFY( fvi ); + fvi(123); + + typedef boost::function FuncMultiArg; + FuncMultiArg fma = hash.get("func"); + VERIFY( fma ); + VERIFY( fma("test", 3, .5) == "test" ); + + //---------------------------------------------------------------------------- + // Test exposing classes to Nasal + //---------------------------------------------------------------------------- + Ghost::init("BasePtr") - .method<&Base::member>("member") - .member("str", &Base::getString, &Base::setString); + .method("member", &Base::member) + .method("strlen", &Base::test1Arg) + .member("str", &Base::getString, &Base::setString) + .method("str_m", &Base::getString) + .method("void", &Base::constVoidFunc) + .member("var_r", &Base::getVar) + .member("var_w", &Base::setVar) + .member("var", &Base::getVar, &Base::setVar) + .method("void", &baseVoidFunc) + .method("void_c", &baseConstVoidFunc) + .method("int2args", &baseFunc2Args) + .method("bool2args", &Base::test2Args) + .method("str_ptr", &testPtr); Ghost::init("DerivedPtr") .bases() .member("x", &Derived::getX, &Derived::setX) .member("x_alternate", &f_derivedGetX) - .method_func<&member>("free_member"); + .method("free_fn", &derivedFreeMember) + .method("free_member", &derivedFreeMember) + .method("baseDoIt", &baseFuncCallContext); Ghost::init("DoubleDerivedPtr") .bases(); Ghost::init("DoubleDerived2Ptr") - .bases< Ghost >(); + .bases< Ghost >() + .member("base", &DoubleDerived2::getBase) + .method("doIt", &DoubleDerived2::doSomeBaseWork); + + Ghost::init("DerivedWeakPtr"); + Ghost::init("SGRefBasedPtr"); + + VERIFY( Ghost::isInit() ); + nasal::to_nasal(c, DoubleDerived2Ptr()); BasePtr d( new Derived ); - naRef derived = Ghost::create(c, d); + naRef derived = to_nasal(c, d); VERIFY( naIsGhost(derived) ); VERIFY( std::string("DerivedPtr") == naGhost_type(derived)->name ); BasePtr d2( new DoubleDerived ); - derived = Ghost::create(c, d2); + derived = to_nasal(c, d2); VERIFY( naIsGhost(derived) ); VERIFY( std::string("DoubleDerivedPtr") == naGhost_type(derived)->name ); BasePtr d3( new DoubleDerived2 ); - derived = Ghost::create(c, d3); + derived = to_nasal(c, d3); VERIFY( naIsGhost(derived) ); VERIFY( std::string("DoubleDerived2Ptr") == naGhost_type(derived)->name ); + SGRefBasedPtr ref_based( new SGReferenceBasedClass ); + naRef na_ref_based = to_nasal(c, ref_based.get()); + VERIFY( naIsGhost(na_ref_based) ); + VERIFY( from_nasal(c, na_ref_based) + == ref_based.get() ); + VERIFY( from_nasal(c, na_ref_based) == ref_based ); + VERIFY( Ghost::isBaseOf(derived) ); VERIFY( Ghost::isBaseOf(derived) ); VERIFY( Ghost::isBaseOf(derived) ); - VERIFY( Ghost::fromNasal(c, derived) == d3 ); - VERIFY( Ghost::fromNasal(c, derived) != d2 ); - VERIFY( Ghost::fromNasal(c, derived) + VERIFY( from_nasal(c, derived) == d3 ); + VERIFY( from_nasal(c, derived) != d2 ); + VERIFY( from_nasal(c, derived) == boost::dynamic_pointer_cast(d3) ); - VERIFY( Ghost::fromNasal(c, derived) + VERIFY( from_nasal(c, derived) == boost::dynamic_pointer_cast(d3) ); - VERIFY( !Ghost::fromNasal(c, derived) ); + VERIFY( !from_nasal(c, derived) ); + + std::map instances; + VERIFY( naIsHash(to_nasal(c, instances)) ); + + std::map instances_d; + VERIFY( naIsHash(to_nasal(c, instances_d)) ); + + std::map int_map; + VERIFY( naIsHash(to_nasal(c, int_map)) ); + + std::map > int_vector_map; + VERIFY( naIsHash(to_nasal(c, int_vector_map)) ); + + simgear::StringMap dict = + simgear::StringMap("hello", "value") + ("key2", "value2"); + naRef na_dict = to_nasal(c, dict); + VERIFY( naIsHash(na_dict) ); + VERIFY( Hash(na_dict, c).get("key2") == "value2" ); // Check converting to Ghost if using Nasal hashes with actual ghost inside // the hashes parents vector @@ -159,27 +272,88 @@ Hash obj(c); obj.set("parents", parents); - VERIFY( Ghost::fromNasal(c, obj.get_naRef()) == d3 ); + VERIFY( from_nasal(c, obj.get_naRef()) == d3 ); // Check recursive parents (aka parent-of-parent) std::vector parents2; parents2.push_back(obj.get_naRef()); Hash derived_obj(c); derived_obj.set("parents", parents2); - VERIFY( Ghost::fromNasal(c, derived_obj.get_naRef()) == d3 ); + VERIFY( from_nasal(c, derived_obj.get_naRef()) == d3 ); + std::vector nasal_objects; + nasal_objects.push_back( Ghost::create(c, d) ); + nasal_objects.push_back( Ghost::create(c, d2) ); + nasal_objects.push_back( Ghost::create(c, d3) ); + naRef obj_vec = to_nasal(c, nasal_objects); + + std::vector objects = from_nasal >(c, obj_vec); + VERIFY( objects[0] == d ); + VERIFY( objects[1] == d2 ); + VERIFY( objects[2] == d3 ); + + // TODO actually do something with the ghosts... + + //---------------------------------------------------------------------------- + // Test nasal::CallContext + //---------------------------------------------------------------------------- + + + int int_vec[] = {1,2,3}; + std::map map; naRef args[] = { - to_nasal(c, std::string("test-arg")) + to_nasal(c, std::string("test-arg")), + to_nasal(c, 4), + to_nasal(c, int_vec), + to_nasal(c, map) }; CallContext cc(c, sizeof(args)/sizeof(args[0]), args); VERIFY( cc.requireArg(0) == "test-arg" ); VERIFY( cc.getArg(0) == "test-arg" ); - VERIFY( cc.getArg(1) == "" ); + VERIFY( cc.getArg(10) == "" ); + VERIFY( cc.isString(0) ); + VERIFY( !cc.isNumeric(0) ); + VERIFY( !cc.isVector(0) ); + VERIFY( !cc.isHash(0) ); + VERIFY( !cc.isGhost(0) ); + VERIFY( cc.isNumeric(1) ); + VERIFY( cc.isVector(2) ); + VERIFY( cc.isHash(3) ); naRef args_vec = nasal::to_nasal(c, args); VERIFY( naIsVector(args_vec) ); - // TODO actually do something with the ghosts... + //---------------------------------------------------------------------------- + // Test nasal::String + //---------------------------------------------------------------------------- + + String string( to_nasal(c, "Test") ); + VERIFY( from_nasal(c, string.get_naRef()) == "Test" ); + VERIFY( string.c_str() == std::string("Test") ); + VERIFY( string.starts_with(string) ); + VERIFY( string.starts_with(String(c, "T")) ); + VERIFY( string.starts_with(String(c, "Te")) ); + VERIFY( string.starts_with(String(c, "Tes")) ); + VERIFY( string.starts_with(String(c, "Test")) ); + VERIFY( !string.starts_with(String(c, "Test1")) ); + VERIFY( !string.starts_with(String(c, "bb")) ); + VERIFY( !string.starts_with(String(c, "bbasdasdafasd")) ); + VERIFY( string.ends_with(String(c, "t")) ); + VERIFY( string.ends_with(String(c, "st")) ); + VERIFY( string.ends_with(String(c, "est")) ); + VERIFY( string.ends_with(String(c, "Test")) ); + VERIFY( !string.ends_with(String(c, "1Test")) ); + VERIFY( !string.ends_with(String(c, "abc")) ); + VERIFY( !string.ends_with(String(c, "estasdasd")) ); + VERIFY( string.find('e') == 1 ); + VERIFY( string.find('9') == String::npos ); + VERIFY( string.find_first_of(String(c, "st")) == 2 ); + VERIFY( string.find_first_of(String(c, "st"), 3) == 3 ); + VERIFY( string.find_first_of(String(c, "xyz")) == String::npos ); + VERIFY( string.find_first_not_of(String(c, "Tst")) == 1 ); + VERIFY( string.find_first_not_of(String(c, "Tse"), 2) == 3 ); + VERIFY( string.find_first_not_of(String(c, "abc")) == 0 ); + VERIFY( string.find_first_not_of(String(c, "abc"), 20) == String::npos ); naFreeContext(c); diff -Nru simgear-2.10.0/simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx simgear-3.0.0/simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx --- simgear-2.10.0/simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,85 @@ +#ifndef SG_FROM_NASAL_HELPER_HXX_ +# error Nasal cppbind - do not include this file! +#endif + +#define n BOOST_PP_ITERATION() + +#ifndef SG_BOOST_FUNCTION_FROM_NASAL_FWD +# define SG_CALL_TRAITS_PARAM(z, n, dummy)\ + typename boost::call_traits::param_type a##n +# define SG_CALL_ARG(z, n, dummy)\ + to_nasal::param_type>(ctx, a##n) + + template< + class Ret + BOOST_PP_COMMA_IF(n) + BOOST_PP_ENUM_PARAMS(n, class A) + > + typename boost::disable_if, Ret>::type + callNasalFunction( const ObjectHolder* holder + BOOST_PP_COMMA_IF(n) + BOOST_PP_ENUM(n, SG_CALL_TRAITS_PARAM, 0) + ) + { + naContext ctx = naNewContext(); + naRef args[] = { + BOOST_PP_ENUM(n, SG_CALL_ARG, 0) + }; + const int num_args = sizeof(args)/sizeof(args[0]); + + naRef result = + naCallMethod(holder->get_naRef(), naNil(), num_args, args, naNil()); + + Ret r = from_nasal_helper(ctx, result, static_cast(0)); + naFreeContext(ctx); + + return r; + } + + template< + class Ret + BOOST_PP_COMMA_IF(n) + BOOST_PP_ENUM_PARAMS(n, class A) + > + typename boost::enable_if, Ret>::type + callNasalFunction( const ObjectHolder* holder + BOOST_PP_COMMA_IF(n) + BOOST_PP_ENUM(n, SG_CALL_TRAITS_PARAM, 0) + ) + { + naContext ctx = naNewContext(); + naRef args[] = { + BOOST_PP_ENUM(n, SG_CALL_ARG, 0) + }; + const int num_args = sizeof(args)/sizeof(args[0]); + + naCallMethod(holder->get_naRef(), naNil(), num_args, args, naNil()); + naFreeContext(ctx); + } + +# undef SG_CALL_TRAITS_PARAM +# undef SG_CALL_ARG +#endif + + template< + class Ret + BOOST_PP_COMMA_IF(n) + BOOST_PP_ENUM_PARAMS(n, class A) + > + boost::function + boostFunctionFromNasal(naRef code, Ret (*)(BOOST_PP_ENUM_PARAMS(n, A))) +#ifdef SG_BOOST_FUNCTION_FROM_NASAL_FWD + ; +#else + { + return boost::bind + ( + &callNasalFunction, + ObjectHolder::makeShared(code) + BOOST_PP_COMMA_IF(n) + BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(n), _) + ); + } +#endif + +#undef n diff -Nru simgear-2.10.0/simgear/nasal/cppbind/detail/from_nasal_helper.cxx simgear-3.0.0/simgear/nasal/cppbind/detail/from_nasal_helper.cxx --- simgear-2.10.0/simgear/nasal/cppbind/detail/from_nasal_helper.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/detail/from_nasal_helper.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,91 @@ +// Conversion functions to convert Nasal types to C++ types +// +// Copyright (C) 2012 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "from_nasal_helper.hxx" +#include +#include + +#include + +namespace nasal +{ + //---------------------------------------------------------------------------- + bad_nasal_cast::bad_nasal_cast(): + sg_exception("conversion failed", "bad_nasal_cast") + { + + } + + //---------------------------------------------------------------------------- + bad_nasal_cast::bad_nasal_cast(const std::string& msg): + sg_exception(msg, "bad_nasal_cast") + { + + } + + //---------------------------------------------------------------------------- + bad_nasal_cast::~bad_nasal_cast() throw() + { + + } + + //---------------------------------------------------------------------------- + std::string from_nasal_helper(naContext c, naRef ref, const std::string*) + { + naRef na_str = naStringValue(c, ref); + + if( naIsNil(na_str) ) + return std::string(); + else if( !naIsString(na_str) ) + throw bad_nasal_cast("Not convertible to string"); + + return std::string(naStr_data(na_str), naStr_len(na_str)); + } + + //---------------------------------------------------------------------------- + SGPath from_nasal_helper(naContext c, naRef ref, const SGPath*) + { + naRef na_str = naStringValue(c, ref); + return SGPath(std::string(naStr_data(na_str), naStr_len(na_str))); + } + + //---------------------------------------------------------------------------- + Hash from_nasal_helper(naContext c, naRef ref, const Hash*) + { + if( !naIsHash(ref) ) + throw bad_nasal_cast("Not a hash"); + + return Hash(ref, c); + } + + //---------------------------------------------------------------------------- + String from_nasal_helper(naContext c, naRef ref, const String*) + { + if( !naIsString(ref) ) + throw bad_nasal_cast("Not a string"); + + return String(ref); + } + + //---------------------------------------------------------------------------- + bool from_nasal_helper(naContext c, naRef ref, const bool*) + { + return naTrue(ref) == 1; + } + +} // namespace nasal diff -Nru simgear-2.10.0/simgear/nasal/cppbind/detail/from_nasal_helper.hxx simgear-3.0.0/simgear/nasal/cppbind/detail/from_nasal_helper.hxx --- simgear-2.10.0/simgear/nasal/cppbind/detail/from_nasal_helper.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/detail/from_nasal_helper.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,203 @@ +///@file +/// Conversion helpers used by from_nasal(naContext, naRef) +/// +// Copyright (C) 2012 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_FROM_NASAL_HELPER_HXX_ +#define SG_FROM_NASAL_HELPER_HXX_ + +#include "nasal_traits.hxx" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +class SGPath; + +namespace nasal +{ + class Hash; + class String; + + /** + * Thrown when converting a type from/to Nasal has failed + */ + class bad_nasal_cast: + public sg_exception + { + public: + /** + * Construct with generic error message + */ + bad_nasal_cast(); + + /** + * Construct from an error message + * + * @param msg Error message/description + */ + explicit bad_nasal_cast(const std::string& msg); + + virtual ~bad_nasal_cast() throw(); + + protected: + std::string _msg; + }; + + /** + * Simple pass through for unified handling also of naRef. + */ + inline naRef from_nasal_helper(naContext, naRef ref, const naRef*) + { return ref; } + + /** + * Convert Nasal string to std::string + */ + std::string from_nasal_helper(naContext c, naRef ref, const std::string*); + + /** + * Convert a Nasal string to an SGPath + */ + SGPath from_nasal_helper(naContext c, naRef ref, const SGPath*); + + /** + * Convert a Nasal hash to a nasal::Hash + */ + Hash from_nasal_helper(naContext c, naRef ref, const Hash*); + + /** + * Convert a Nasal string to a nasal::String + */ + String from_nasal_helper(naContext c, naRef ref, const String*); + + /** + * Convert a Nasal object to bool. + * + * @return true, if ref is string or ref is number != 0 + * false, else + */ + bool from_nasal_helper(naContext c, naRef ref, const bool*); + + namespace detail + { +#define SG_BOOST_FUNCTION_FROM_NASAL_FWD +#define BOOST_PP_ITERATION_LIMITS (0, 9) +#define BOOST_PP_FILENAME_1 +#include BOOST_PP_ITERATE() +#undef SG_BOOST_FUNCTION_FROM_NASAL_FWD + } + + /** + * Convert a Nasal function to a boost::function with the given signature. + * + * @tparam Sig Signature of returned function (arguments and return value + * are automatically converted using from_nasal/to_nasal) + */ + template + boost::function + from_nasal_helper(naContext c, naRef ref, boost::function*) + { + if( !naIsCode(ref) + && !naIsCCode(ref) + && !naIsFunc(ref) ) + throw bad_nasal_cast("not a function"); + + return detail::boostFunctionFromNasal(ref, static_cast(0)); + } + + template + typename boost::enable_if< boost::is_function, + boost::function + >::type + from_nasal_helper(naContext c, naRef ref, Sig*) + { + return from_nasal_helper(c, ref, static_cast*>(0)); + } + + /** + * Convert a Nasal number to a C++ numeric type + */ + template + typename boost::enable_if< boost::is_arithmetic, + T + >::type + from_nasal_helper(naContext c, naRef ref, const T*) + { + naRef num = naNumValue(ref); + if( !naIsNum(num) ) + throw bad_nasal_cast("Not a number"); + + return static_cast(num.num); + } + + /** + * Convert a Nasal vector to a std::vector + */ + template + std::vector + from_nasal_helper(naContext c, naRef ref, const std::vector*) + { + if( !naIsVector(ref) ) + throw bad_nasal_cast("Not a vector"); + + int size = naVec_size(ref); + std::vector vec(size); + + for(int i = 0; i < size; ++i) + vec[i] = from_nasal_helper(c, naVec_get(ref, i), static_cast(0)); + + return vec; + } + + /** + * Convert a Nasal vector of 2 elements to a 2d vector + */ + template + typename boost::enable_if, Vec2>::type + from_nasal_helper(naContext c, naRef ref, const Vec2*) + { + std::vector vec = + from_nasal_helper(c, ref, static_cast*>(0)); + if( vec.size() != 2 ) + throw bad_nasal_cast("Expected vector with two elements"); + return Vec2(vec[0], vec[1]); + } + + // Helpers for wrapping calls to Nasal functions into boost::function + namespace detail + { +#define BOOST_PP_ITERATION_LIMITS (0, 9) +#define BOOST_PP_FILENAME_1 +#include BOOST_PP_ITERATE() + } + +} // namespace nasal + +#endif /* SG_FROM_NASAL_HELPER_HXX_ */ diff -Nru simgear-2.10.0/simgear/nasal/cppbind/detail/functor_templates.hxx simgear-3.0.0/simgear/nasal/cppbind/detail/functor_templates.hxx --- simgear-2.10.0/simgear/nasal/cppbind/detail/functor_templates.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/detail/functor_templates.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,104 @@ +#ifndef SG_NASAL_GHOST_HXX_ +# error Nasal cppbind - do not include this file! +#endif + +#define n BOOST_PP_ITERATION() + +#define SG_GHOST_FUNC_TYPE\ + boost::function + + /** + * Bind any callable entity accepting an instance of raw_type and an arbitrary + * number of arguments as method. + */ + template< + class Ret + BOOST_PP_COMMA_IF(n) + BOOST_PP_ENUM_PARAMS(n, class A) + > + Ghost& method(const std::string& name, const SG_GHOST_FUNC_TYPE& func) + { +#if defined(SG_GCC_VERSION) && SG_GCC_VERSION < 40407 + // The old version of g++ used on Jenkins (16.11.2012) only compiles this + // version. +# define SG_GHOST_REQUIRE_ARG(z, n, dummy)\ + boost::bind(&arg_from_nasal, _2, n) +#else + // VS (2008, 2010, ... ?) only allow this version. +# define SG_GHOST_REQUIRE_ARG(z, n, dummy)\ + boost::bind(&Ghost::arg_from_nasal, _2, n) +#endif + + return method + ( + name, + typename boost::function + ( boost::bind( + func, + _1 + BOOST_PP_COMMA_IF(n) + BOOST_PP_ENUM(n, SG_GHOST_REQUIRE_ARG, 0) + )) + ); + +#undef SG_GHOST_REQUIRE_ARG + } + +#define SG_GHOST_MEM_FN(cv)\ + /**\ + * Bind a member function with an arbitrary number of arguments as method.\ + */\ + template<\ + class Ret\ + BOOST_PP_COMMA_IF(n)\ + BOOST_PP_ENUM_PARAMS(n, class A)\ + >\ + Ghost& method\ + (\ + const std::string& name,\ + Ret (raw_type::*fn)(BOOST_PP_ENUM_PARAMS(n,A)) cv\ + )\ + {\ + return method<\ + Ret\ + BOOST_PP_COMMA_IF(n)\ + BOOST_PP_ENUM_PARAMS(n,A)\ + >(name, SG_GHOST_FUNC_TYPE(fn));\ + } + +// Work around MSVC warning C4003: not enough actual parameters for macro +// We really do not want to pass a parameter, even if MSVC can not believe it. +#define SG_GHOST_NO_CV + + SG_GHOST_MEM_FN(const) + SG_GHOST_MEM_FN(SG_GHOST_NO_CV) + +#undef SG_GHOST_MEM_FN +#undef SG_GHOST_NO_CV + + /** + * Bind free function accepting an instance of raw_type and an arbitrary + * number of arguments as method. + */ + template< + class Ret, + class Type + BOOST_PP_COMMA_IF(n) + BOOST_PP_ENUM_PARAMS(n, class A) + > + Ghost& method + ( + const std::string& name, + Ret (*fn)(Type BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n,A)) + ) + { + BOOST_STATIC_ASSERT + (( boost::is_convertible::value + //|| boost::is_convertible::value + // TODO check how to do it with pointer... + )); + return method(name, SG_GHOST_FUNC_TYPE(fn)); + } + +#undef n +#undef SG_GHOST_TYPEDEF_FUNC_TYPE diff -Nru simgear-2.10.0/simgear/nasal/cppbind/detail/nasal_traits.hxx simgear-3.0.0/simgear/nasal/cppbind/detail/nasal_traits.hxx --- simgear-2.10.0/simgear/nasal/cppbind/detail/nasal_traits.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/detail/nasal_traits.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,58 @@ +///@file +/// Type traits used for converting from and to Nasal types +/// +// Copyright (C) 2012 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_NASAL_TRAITS_HXX_ +#define SG_NASAL_TRAITS_HXX_ + +#include + +namespace nasal +{ + template + struct is_vec2: public boost::integral_constant {}; + +#define SG_MAKE_TRAIT(templ,type,attr)\ + template templ\ + struct attr< type >:\ + public boost::integral_constant {}; + +#ifdef SGVec2_H + SG_MAKE_TRAIT(, SGVec2, is_vec2) +#endif + +#ifdef OSG_VEC2B + SG_MAKE_TRAIT(<>, osg::Vec2b, is_vec2) +#endif + +#ifdef OSG_VEC2D + SG_MAKE_TRAIT(<>, osg::Vec2d, is_vec2) +#endif + +#ifdef OSG_VEC2F + SG_MAKE_TRAIT(<>, osg::Vec2f, is_vec2) +#endif + +#ifdef OSG_VEC2S + SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2) +#endif + +#undef SG_MAKE_TRAIT + +} // namespace nasal +#endif /* SG_NASAL_TRAITS_HXX_ */ diff -Nru simgear-2.10.0/simgear/nasal/cppbind/detail/to_nasal_helper.cxx simgear-3.0.0/simgear/nasal/cppbind/detail/to_nasal_helper.cxx --- simgear-2.10.0/simgear/nasal/cppbind/detail/to_nasal_helper.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/detail/to_nasal_helper.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,126 @@ +// Conversion functions to convert C++ types to Nasal types +// +// Copyright (C) 2012 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "to_nasal_helper.hxx" +#include +#include + +#include +#include + +#include + +namespace nasal +{ + //---------------------------------------------------------------------------- + naRef to_nasal_helper(naContext c, const std::string& str) + { + naRef ret = naNewString(c); + naStr_fromdata(ret, str.c_str(), static_cast(str.size())); + return ret; + } + + //---------------------------------------------------------------------------- + naRef to_nasal_helper(naContext c, const char* str) + { + return to_nasal_helper(c, std::string(str)); + } + + //---------------------------------------------------------------------------- + naRef to_nasal_helper(naContext c, const Hash& hash) + { + return hash.get_naRef(); + } + + //---------------------------------------------------------------------------- + naRef to_nasal_helper(naContext c, const naRef& ref) + { + return ref; + } + + //------------------------------------------------------------------------------ + naRef to_nasal_helper(naContext c, const SGGeod& pos) + { + nasal::Hash hash(c); + hash.set("lat", pos.getLatitudeDeg()); + hash.set("lon", pos.getLongitudeDeg()); + hash.set("elevation", pos.getElevationM()); + return hash.get_naRef(); + } + + //---------------------------------------------------------------------------- + naRef to_nasal_helper(naContext c, const SGPath& path) + { + return to_nasal_helper(c, path.str()); + } + + //---------------------------------------------------------------------------- + naRef to_nasal_helper(naContext c, naCFunction func) + { + return naNewFunc(c, naNewCCode(c, func)); + } + + //---------------------------------------------------------------------------- + static naRef free_function_invoker( naContext c, + naRef me, + int argc, + naRef* args, + void* user_data ) + { + free_function_t* func = static_cast(user_data); + assert(func); + + try + { + return (*func)(nasal::CallContext(c, argc, args)); + } + catch(const std::exception& ex) + { + naRuntimeError(c, "Fatal error in Nasal call: %s", ex.what()); + } + catch(...) + { + naRuntimeError(c, "Unknown exception in Nasal call."); + } + + return naNil(); + } + + //---------------------------------------------------------------------------- + static void free_function_destroy(void* func) + { + delete static_cast(func); + } + + //---------------------------------------------------------------------------- + naRef to_nasal_helper(naContext c, const free_function_t& func) + { + return naNewFunc + ( + c, + naNewCCodeUD + ( + c, + &free_function_invoker, + new free_function_t(func), + &free_function_destroy + ) + ); + } + +} // namespace nasal diff -Nru simgear-2.10.0/simgear/nasal/cppbind/detail/to_nasal_helper.hxx simgear-3.0.0/simgear/nasal/cppbind/detail/to_nasal_helper.hxx --- simgear-2.10.0/simgear/nasal/cppbind/detail/to_nasal_helper.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/detail/to_nasal_helper.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,182 @@ +///@file +/// Conversion helpers used by to_nasal(naContext, T) +/// +// Copyright (C) 2012 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_TO_NASAL_HELPER_HXX_ +#define SG_TO_NASAL_HELPER_HXX_ + +#include "nasal_traits.hxx" + +#include + +#include +#include +#include +#include + +#include +#include +#include + +class SGGeod; +class SGPath; + +namespace nasal +{ + class CallContext; + class Hash; + + typedef boost::function free_function_t; + + /** + * Convert std::string to Nasal string + */ + naRef to_nasal_helper(naContext c, const std::string& str); + + /** + * Convert C-string to Nasal string + */ + // We need this to prevent the array overload of to_nasal being called + naRef to_nasal_helper(naContext c, const char* str); + + /** + * Convert a nasal::Hash to a Nasal hash + */ + naRef to_nasal_helper(naContext c, const Hash& hash); + + /** + * Simple pass-through of naRef types to allow generic usage of to_nasal + */ + naRef to_nasal_helper(naContext c, const naRef& ref); + + naRef to_nasal_helper(naContext c, const SGGeod& pos); + + naRef to_nasal_helper(naContext c, const SGPath& path); + + /** + * Convert function pointer to Nasal function + */ + naRef to_nasal_helper(naContext c, naCFunction func); + + naRef to_nasal_helper(naContext c, const free_function_t& func); + + /** + * Convert an enum value to the according numeric value + */ + template + typename boost::enable_if< boost::is_enum, naRef >::type + to_nasal_helper(naContext c, T val) + { + return naNum(val); + } + + /** + * Convert a numeric type to Nasal number + */ + template + typename boost::enable_if< boost::is_arithmetic, naRef >::type + to_nasal_helper(naContext c, T num) + { + return naNum(num); + } + + /** + * Convert a 2d vector to Nasal vector with 2 elements + */ + template + typename boost::enable_if, naRef>::type + to_nasal_helper(naContext c, const Vec2& vec); + + /** + * Convert a std::map to a Nasal Hash + */ + template + naRef to_nasal_helper(naContext c, const std::map& map); + + /** + * Convert a fixed size array to a Nasal vector + */ + template + naRef to_nasal_helper(naContext c, const T(&array)[N]); + + /** + * Convert std::vector to Nasal vector + */ + template< template class Vector, + class T, + class Alloc + > + typename boost::enable_if< boost::is_same< Vector, + std::vector + >, + naRef + >::type + to_nasal_helper(naContext c, const Vector& vec) + { + naRef ret = naNewVector(c); + naVec_setsize(c, ret, static_cast(vec.size())); + for(int i = 0; i < static_cast(vec.size()); ++i) + naVec_set(ret, i, to_nasal_helper(c, vec[i])); + return ret; + } + + //---------------------------------------------------------------------------- + template + typename boost::enable_if, naRef>::type + to_nasal_helper(naContext c, const Vec2& vec) + { + // We take just double because in Nasal every number is represented as + // double + double nasal_vec[2] = {vec[0], vec[1]}; + return to_nasal_helper(c, nasal_vec); + } + + //---------------------------------------------------------------------------- + template + naRef to_nasal_helper(naContext c, const std::map& map) + { + naRef hash = naNewHash(c); + + typedef typename boost::call_traits::param_type param_type; + typedef typename std::map::const_iterator map_iterator; + + for( map_iterator it = map.begin(); it != map.end(); ++it ) + naHash_set + ( + hash, + to_nasal_helper(c, it->first), + to_nasal_helper(c, static_cast(it->second)) + ); + + return hash; + } + + //---------------------------------------------------------------------------- + template + naRef to_nasal_helper(naContext c, const T(&array)[N]) + { + naRef ret = naNewVector(c); + naVec_setsize(c, ret, static_cast(N)); + for(int i = 0; i < static_cast(N); ++i) + naVec_set(ret, i, to_nasal_helper(c, array[i])); + return ret; + } + +} // namespace nasal + +#endif /* SG_TO_NASAL_HELPER_HXX_ */ diff -Nru simgear-2.10.0/simgear/nasal/cppbind/from_nasal.cxx simgear-3.0.0/simgear/nasal/cppbind/from_nasal.cxx --- simgear-2.10.0/simgear/nasal/cppbind/from_nasal.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/from_nasal.cxx 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -// Conversion functions to convert Nasal types to C++ types -// -// Copyright (C) 2012 Thomas Geymayer -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - -#include "from_nasal_detail.hxx" -#include "NasalHash.hxx" - -#include - -namespace nasal -{ - //---------------------------------------------------------------------------- - bad_nasal_cast::bad_nasal_cast() - { - - } - - //---------------------------------------------------------------------------- - bad_nasal_cast::bad_nasal_cast(const std::string& msg): - _msg( msg ) - { - - } - - //---------------------------------------------------------------------------- - bad_nasal_cast::~bad_nasal_cast() throw() - { - - } - - //---------------------------------------------------------------------------- - const char* bad_nasal_cast::what() const throw() - { - return _msg.empty() ? bad_cast::what() : _msg.c_str(); - } - - //---------------------------------------------------------------------------- - std::string from_nasal_helper(naContext c, naRef ref, std::string*) - { - naRef na_str = naStringValue(c, ref); - return std::string(naStr_data(na_str), naStr_len(na_str)); - } - - SGPath from_nasal_helper(naContext c, naRef ref, SGPath*) - { - naRef na_str = naStringValue(c, ref); - return SGPath(std::string(naStr_data(na_str), naStr_len(na_str))); - } - - //---------------------------------------------------------------------------- - Hash from_nasal_helper(naContext c, naRef ref, Hash*) - { - if( !naIsHash(ref) ) - throw bad_nasal_cast("Not a hash"); - - return Hash(ref, c); - } - -} // namespace nasal diff -Nru simgear-2.10.0/simgear/nasal/cppbind/from_nasal_detail.hxx simgear-3.0.0/simgear/nasal/cppbind/from_nasal_detail.hxx --- simgear-2.10.0/simgear/nasal/cppbind/from_nasal_detail.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/from_nasal_detail.hxx 1970-01-01 00:00:00.000000000 +0000 @@ -1,140 +0,0 @@ -///@file -/// Conversion helpers used by from_nasal(naContext, naRef) -/// -// Copyright (C) 2012 Thomas Geymayer -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - -#ifndef SG_FROM_NASAL_DETAIL_HXX_ -#define SG_FROM_NASAL_DETAIL_HXX_ - -#include "nasal_traits.hxx" - -#include - -#include -#include - -#include -#include // std::bad_cast -#include - -class SGPath; - -namespace nasal -{ - class Hash; - - /** - * Thrown when converting a type from/to Nasal has failed - */ - class bad_nasal_cast: - public std::bad_cast - { - public: - /** - * Construct with generic error message - */ - bad_nasal_cast(); - - /** - * Construct from an error message - * - * @param msg Error message/description - */ - explicit bad_nasal_cast(const std::string& msg); - - virtual ~bad_nasal_cast() throw(); - - /** - * Get a description of the cause of the failed cast. - */ - virtual const char* what() const throw(); - - protected: - std::string _msg; - }; - - /** - * Simple pass through for unified handling also of naRef. - */ - inline naRef from_nasal_helper(naContext, naRef ref, naRef*) { return ref; } - - /** - * Convert Nasal string to std::string - */ - std::string from_nasal_helper(naContext c, naRef ref, std::string*); - - /** - * Convert a Nasal string to an SGPath - */ - SGPath from_nasal_helper(naContext c, naRef ref, SGPath*); - - /** - * Convert a Nasal hash to a nasal::Hash - */ - Hash from_nasal_helper(naContext c, naRef ref, Hash*); - - /** - * Convert a Nasal number to a C++ numeric type - */ - template - typename boost::enable_if< boost::is_arithmetic, - T - >::type - from_nasal_helper(naContext c, naRef ref, T*) - { - naRef num = naNumValue(ref); - if( !naIsNum(num) ) - throw bad_nasal_cast("Not a number"); - - return static_cast(num.num); - } - - /** - * Convert a Nasal vector to a std::vector - */ - template - std::vector from_nasal_helper(naContext c, naRef ref, std::vector*) - { - if( !naIsVector(ref) ) - throw bad_nasal_cast("Not a vector"); - - int size = naVec_size(ref); - std::vector vec(size); - - for(int i = 0; i < size; ++i) - vec[i] = from_nasal_helper(c, naVec_get(ref, i), static_cast(0)); - - return vec; - } - - /** - * Convert a Nasal vector of 2 elements to a 2d vector - */ - template - typename boost::enable_if, Vec2>::type - from_nasal_helper(naContext c, naRef ref, Vec2*) - { - std::vector vec = - from_nasal_helper(c, ref, static_cast*>(0)); - if( vec.size() != 2 ) - throw bad_nasal_cast("Expected vector with two elements"); - return Vec2(vec[0], vec[1]); - } - -} // namespace nasal - -#endif /* SG_FROM_NASAL_DETAIL_HXX_ */ diff -Nru simgear-2.10.0/simgear/nasal/cppbind/from_nasal.hxx simgear-3.0.0/simgear/nasal/cppbind/from_nasal.hxx --- simgear-2.10.0/simgear/nasal/cppbind/from_nasal.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/from_nasal.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -20,7 +20,7 @@ #ifndef SG_FROM_NASAL_HXX_ #define SG_FROM_NASAL_HXX_ -#include "from_nasal_detail.hxx" +#include namespace nasal { @@ -45,6 +45,24 @@ return from_nasal_helper(c, ref, static_cast(0)); } + /** + * Get pointer to specific version of from_nasal, converting to a type + * compatible to Var. + */ + template + struct from_nasal_ptr + { + typedef typename boost::remove_const + < typename boost::remove_reference::type + >::type return_type; + typedef return_type(*type)(naContext, naRef); + + static type get() + { + return &from_nasal; + } + }; + } // namespace nasal #endif /* SG_FROM_NASAL_HXX_ */ diff -Nru simgear-2.10.0/simgear/nasal/cppbind/Ghost.hxx simgear-3.0.0/simgear/nasal/cppbind/Ghost.hxx --- simgear-2.10.0/simgear/nasal/cppbind/Ghost.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/Ghost.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -20,8 +20,8 @@ #ifndef SG_NASAL_GHOST_HXX_ #define SG_NASAL_GHOST_HXX_ -#include "from_nasal.hxx" -#include "to_nasal.hxx" +#include "NasalCallContext.hxx" +#include "NasalObjectHolder.hxx" #include @@ -30,10 +30,18 @@ #include #include #include +#include +#include #include #include +template +inline T* get_pointer(boost::weak_ptr const& p) +{ + return p.lock().get(); +} + /** * Bindings between C++ and the Nasal scripting language */ @@ -60,7 +68,7 @@ bool isBaseOf(naGhostType* ghost_type) const { - if( ghost_type == &_ghost_type ) + if( ghost_type == _ghost_type_ptr ) return true; for( DerivedList::const_iterator derived = _derived_classes.begin(); @@ -79,12 +87,14 @@ typedef std::vector DerivedList; const std::string _name; - naGhostType _ghost_type; + const naGhostType *_ghost_type_ptr; DerivedList _derived_classes; std::vector _parents; - explicit GhostMetadata(const std::string& name): - _name(name) + GhostMetadata( const std::string& name, + const naGhostType* ghost_type ): + _name(name), + _ghost_type_ptr(ghost_type) { } @@ -98,7 +108,7 @@ ( SG_NASAL, SG_INFO, - "Ghost::addDerived: " <<_ghost_type.name << " -> " << derived->_name + "Ghost::addDerived: " << _name << " -> " << derived->_name ); } @@ -108,54 +118,42 @@ } }; - BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type) - } - - /** - * Context passed to a function/method being called from Nasal - */ - struct CallContext - { - CallContext(naContext c, size_t argc, naRef* args): - c(c), - argc(argc), - args(args) - {} - /** - * Get the argument with given index if it exists. Otherwise returns the - * passed default value. - * - * @tparam T Type of argument (converted using ::from_nasal) - * @param index Index of requested argument - * @param def Default value returned if too few arguments available + * Hold callable method and convert to Nasal function if required. */ - template - T getArg(size_t index, const T& def = T()) const + class MethodHolder { - if( index >= argc ) - return def; + public: + virtual ~MethodHolder() {} - return from_nasal(c, args[index]); - } + naRef get_naRef(naContext c) + { + if( !_obj ) + _obj = ObjectHolder::makeShared(createNasalObject(c)); + return _obj->get_naRef(); + } + + protected: + ObjectHolderRef _obj; + + virtual naRef createNasalObject(naContext c) = 0; + }; + + BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type) - /** - * Get the argument with given index. Raises a Nasal runtime error if there - * are to few arguments available. - */ template - T requireArg(size_t index) const + struct reduced_type { - if( index >= argc ) - naRuntimeError(c, "Missing required arg #%d", index); - - return from_nasal(c, args[index]); - } + typedef typename boost::remove_cv< + typename boost::remove_reference::type + >::type type; + }; - naContext c; - size_t argc; - naRef *args; - }; + template + struct reduced_is_same: + public boost::is_same::type, T2> + {}; + } /** * Class for exposing C++ objects to Nasal @@ -168,10 +166,13 @@ * void setX(int x); * int getX() const; * - * naRef myMember(naContext c, int argc, naRef* args); + * int myMember(); + * void doSomethingElse(const nasal::CallContext& ctx); * } * typedef boost::shared_ptr MyClassPtr; * + * std::string myOtherFreeMember(int num); + * * void exposeClasses() * { * // Register a nasal ghost type for MyClass. This needs to be done only @@ -184,9 +185,12 @@ * .member("x_readonly", &MyClass::getX) * // It is also possible to expose writeonly members * .member("x_writeonly", &MyClass::setX) - * // Methods use a slightly different syntax - The pointer to the member - * // function has to be passed as template argument - * .method<&MyClass::myMember>("myMember"); + * // Methods can be nearly anything callable and accepting a reference + * // to an instance of the class type. (member functions, free functions + * // and anything else bindable using boost::function and boost::bind) + * .method("myMember", &MyClass::myMember) + * .method("doSomething", &MyClass::doSomethingElse) + * .method("other", &myOtherFreeMember); * } * @endcode */ @@ -197,12 +201,61 @@ BOOST_STATIC_ASSERT( internal::has_element_type::value ); public: - typedef typename T::element_type raw_type; - typedef T pointer; + typedef typename T::element_type raw_type; + typedef T pointer; typedef naRef (raw_type::*member_func_t)(const CallContext&); typedef naRef (*free_func_t)(raw_type&, const CallContext&); - typedef boost::function getter_t; - typedef boost::function setter_t; + typedef boost::function getter_t; + typedef boost::function setter_t; + typedef boost::function method_t; + typedef boost::shared_ptr MethodHolderPtr; + + class MethodHolder: + public internal::MethodHolder + { + public: + explicit MethodHolder(const method_t& method): + _method(method) + {} + + protected: + method_t _method; + + virtual naRef createNasalObject(naContext c) + { + return naNewFunc(c, naNewCCodeU(c, &MethodHolder::call, this)); + } + + static naRef call( naContext c, + naRef me, + int argc, + naRef* args, + void* user_data ) + { + MethodHolder* holder = static_cast(user_data); + if( !holder ) + naRuntimeError(c, "invalid method holder!"); + + try + { + return holder->_method + ( + requireObject(c, me), + CallContext(c, argc, args) + ); + } + catch(const std::exception& ex) + { + naRuntimeError(c, "Fatal error in method call: %s", ex.what()); + } + catch(...) + { + naRuntimeError(c, "Unknown exception in method call."); + } + + return naNil(); + } + }; /** * A ghost member. Can consist either of getter and/or setter functions @@ -210,25 +263,24 @@ */ struct member_t { - member_t(): - func(0) + member_t() {} member_t( const getter_t& getter, const setter_t& setter, - naCFunction func = 0 ): + const MethodHolderPtr& func = MethodHolderPtr() ): getter( getter ), setter( setter ), func( func ) {} - member_t(naCFunction func): + explicit member_t(const MethodHolderPtr& func): func( func ) {} - getter_t getter; - setter_t setter; - naCFunction func; + getter_t getter; + setter_t setter; + MethodHolderPtr func; }; typedef std::map MemberMap; @@ -242,13 +294,19 @@ */ static Ghost& init(const std::string& name) { - assert( !getSingletonPtr() ); - getSingletonHolder().reset( new Ghost(name) ); return *getSingletonPtr(); } /** + * Check whether ghost type has already been initialized. + */ + static bool isInit() + { + return getSingletonPtr(); + } + + /** * Register a base class for this ghost. The base class needs to be * registers on its own before it can be used as base class. * @@ -281,7 +339,7 @@ // Both ways of retrieving the address of a static member function // should be legal but not all compilers know this. // g++-4.4.7+ has been tested to work with both versions -#if defined(GCC_VERSION) && GCC_VERSION < 40407 +#if defined(SG_GCC_VERSION) && SG_GCC_VERSION < 40407 // The old version of g++ used on Jenkins (16.11.2012) only compiles // this version. &getTypeFor @@ -357,30 +415,25 @@ * @param setter Setter for variable (Pass 0 to prevent write access) * */ - template + template Ghost& member( const std::string& field, - Var (raw_type::*getter)() const, - void (raw_type::*setter)(typename boost::call_traits::param_type) = 0 ) + Ret (raw_type::*getter)() const, + void (raw_type::*setter)(Param) ) { - member_t m; - if( getter ) - { - typedef typename boost::call_traits::param_type param_type; - naRef (*to_nasal_)(naContext, param_type) = &nasal::to_nasal; - - // Getter signature: naRef(naContext, raw_type&) - m.getter = boost::bind(to_nasal_, _1, boost::bind(getter, _2)); - } - - if( setter ) - { - Var (*from_nasal_)(naContext, naRef) = &nasal::from_nasal; - - // Setter signature: void(naContext, raw_type&, naRef) - m.setter = boost::bind(setter, _2, boost::bind(from_nasal_, _1, _3)); - } + return member(field, to_getter(getter), to_setter(setter)); + } - return member(field, m.getter, m.setter); + /** + * Register a read only member variable. + * + * @param field Name of member + * @param getter Getter for variable + */ + template + Ghost& member( const std::string& field, + Ret (raw_type::*getter)() const ) + { + return member(field, to_getter(getter), setter_t()); } /** @@ -393,7 +446,7 @@ Ghost& member( const std::string& field, void (raw_type::*setter)(Var) ) { - return member(field, 0, setter); + return member(field, getter_t(), to_setter(setter)); } /** @@ -421,67 +474,54 @@ } /** - * Register a member function. - * - * @note Because only function pointers can be registered as Nasal - * functions it is needed to pass the function pointer as template - * argument. This allows us to create a separate instance of the - * MemberFunctionWrapper for each registered function and therefore - * provides us with the needed static functions to be passed on to - * Nasal. - * - * @tparam func Pointer to member function being registered. + * Register anything that accepts an object instance and a + * nasal::CallContext and returns naRef as method. * * @code{cpp} * class MyClass * { * public: - * naRef myMethod(naContext c, int argc, naRef* args); + * naRef myMethod(const nasal::CallContext& ctx); * } * * Ghost::init("Test") - * .method<&MyClass::myMethod>("myMethod"); + * .method("myMethod", &MyClass::myMethod); * @endcode */ - template - Ghost& method(const std::string& name) + Ghost& method(const std::string& name, const method_t& func) { - _members[name].func = &MemberFunctionWrapper::call; + _members[name].func.reset( new MethodHolder(func) ); return *this; } /** - * Register a free function as member function. The object instance is - * passed as additional first argument. - * - * @tparam func Pointer to free function being registered. - * - * @note Due to a severe bug in Visual Studio it is not possible to create - * a specialization of #method for free function pointers and - * member function pointers at the same time. Do overcome this - * limitation we had to use a different name for this function. + * Register anything that accepts an object instance and a + * nasal::CallContext whith automatic conversion of the return type to + * Nasal. * * @code{cpp} * class MyClass; - * naRef myMethod(MyClass& obj, naContext c, int argc, naRef* args); + * void doIt(const MyClass& c, const nasal::CallContext& ctx); * * Ghost::init("Test") - * .method_func<&myMethod>("myMethod"); + * .method("doIt", &doIt); * @endcode */ - template - Ghost& method_func(const std::string& name) - { - _members[name].func = &FreeFunctionWrapper::call; - return *this; + template + Ghost& method + ( + const std::string& name, + const boost::function& func + ) + { + return method(name, boost::bind(method_invoker, func, _1, _2)); } +#define BOOST_PP_ITERATION_LIMITS (0, 9) +#define BOOST_PP_FILENAME_1 +#include BOOST_PP_ITERATE() + // TODO use variadic template when supporting C++11 - /** - * Create a Nasal instance of this ghost. - * - * @param c Active Nasal context - */ // TODO check if default constructor exists // static naRef create( naContext c ) // { @@ -549,7 +589,7 @@ ++parent ) { pointer ptr = fromNasal(c, *parent); - if( ptr ) + if( get_pointer(ptr) ) return ptr; } } @@ -562,6 +602,8 @@ template friend class Ghost; + static naGhostType _ghost_type; + typedef naGhostType* (*type_checker_t)(const raw_type*); typedef std::vector DerivedList; DerivedList _derived_types; @@ -572,7 +614,7 @@ */ static pointer* createInstance(const pointer& ptr) { - return ptr ? new pointer(ptr) : 0; + return get_pointer(ptr) ? new pointer(ptr) : 0; } static pointer getPtr(void* ptr) @@ -586,14 +628,14 @@ static raw_type* getRawPtr(void* ptr) { if( ptr ) - return static_cast(ptr)->get(); + return get_pointer(*static_cast(ptr)); else return 0; } static raw_type* getRawPtr(const pointer& ptr) { - return ptr.get(); + return get_pointer(ptr); } void addDerived( const internal::GhostMetadata* derived_meta, @@ -634,7 +676,7 @@ // If base is not an instance of any derived class, this class has to // be the dynamic type. - return &getSingletonPtr()->_ghost_type; + return &_ghost_type; } template @@ -647,7 +689,7 @@ { // For non polymorphic classes there is no possibility to get the actual // dynamic type, therefore we can only use its static type. - return &BaseGhost::getSingletonPtr()->_ghost_type; + return &BaseGhost::_ghost_type; } static Ghost* getSingletonPtr() @@ -666,58 +708,110 @@ c, "method called on object of wrong type: is '%s' expected '%s'", ghost_type ? ghost_type->name : "unknown", - getSingletonPtr()->_ghost_type.name + _ghost_type.name ); return *obj; } + template + getter_t to_getter(Ret (raw_type::*getter)() const) + { + typedef typename boost::call_traits::param_type param_type; + naRef(*to_nasal_)(naContext, param_type) = &to_nasal; + + // Getter signature: naRef(naContext, raw_type&) + return boost::bind + ( + to_nasal_, + _1, + boost::bind(getter, _2) + ); + } + + template + setter_t to_setter(void (raw_type::*setter)(Param)) + { + // Setter signature: void(naContext, raw_type&, naRef) + return boost::bind + ( + setter, + _2, + boost::bind(from_nasal_ptr::get(), _1, _3) + ); + } + + /** - * Wrapper class to enable registering pointers to member functions as - * Nasal function callbacks. We need to use the function pointer as - * template parameter to ensure every registered function gets a static - * function which can be passed to Nasal. + * Invoke a method which returns a value and convert it to Nasal. */ - template - struct MemberFunctionWrapper + template + static + typename boost::disable_if, naRef>::type + method_invoker + ( + const boost::function& func, + raw_type& obj, + const CallContext& ctx + ) { - /** - * Called from Nasal upon invocation of the according registered - * function. Forwards the call to the passed object instance. - */ - static naRef call(naContext c, naRef me, int argc, naRef* args) - { - return (requireObject(c, me).*func)(CallContext(c, argc, args)); - } + return (*to_nasal_ptr::get())(ctx.c, func(obj, ctx)); }; /** - * Wrapper class to enable registering pointers to free functions (only - * external linkage). We need to use the function pointer as template - * parameter to ensure every registered function gets a static function - * which can be passed to Nasal. Even though we just wrap another simple - * function pointer this intermediate step is need to be able to retrieve - * the object the function call belongs to and pass it along as argument. + * Invoke a method which returns void and "convert" it to nil. */ - template - struct FreeFunctionWrapper + template + static + typename boost::enable_if, naRef>::type + method_invoker + ( + const boost::function& func, + raw_type& obj, + const CallContext& ctx + ) { - /** - * Called from Nasal upon invocation of the according registered - * function. Forwards the call to the passed function pointer and passes - * the required parameters. - */ - static naRef call(naContext c, naRef me, int argc, naRef* args) - { - return func(requireObject(c, me), CallContext(c, argc, args)); - } + func(obj, ctx); + return naNil(); + }; + + /** + * Extract argument by index from nasal::CallContext and convert to given + * type. + */ + template + static + typename boost::disable_if< + internal::reduced_is_same, + typename from_nasal_ptr::return_type + >::type + arg_from_nasal(const CallContext& ctx, size_t index) + { + return ctx.requireArg(index); + }; + + /** + * Specialization to pass through nasal::CallContext. + */ + template + static + typename boost::enable_if< + internal::reduced_is_same, + typename from_nasal_ptr::return_type + >::type + arg_from_nasal(const CallContext& ctx, size_t) + { + // Either const CallContext& or CallContext, non-const reference + // does not make sense. + BOOST_STATIC_ASSERT( (!boost::is_same::value) ); + return ctx; }; typedef std::auto_ptr GhostPtr; MemberMap _members; explicit Ghost(const std::string& name): - GhostMetadata( name ) + GhostMetadata(name, &_ghost_type) { _ghost_type.destroy = &destroyGhost; _ghost_type.name = _name.c_str(); @@ -776,7 +870,7 @@ return 0; if( member->second.func ) - *out = nasal::to_nasal(c, member->second.func); + *out = member->second.func->get_naRef(c); else if( !member->second.getter.empty() ) *out = member->second.getter(c, *getRawPtr(g)); else @@ -796,13 +890,73 @@ if( member == getSingletonPtr()->_members.end() ) naRuntimeError(c, "ghost: No such member: %s", key.c_str()); - if( member->second.setter.empty() ) + else if( member->second.setter.empty() ) naRuntimeError(c, "ghost: Write protected member: %s", key.c_str()); + else if( member->second.func ) + naRuntimeError(c, "ghost: Write to function: %s", key.c_str()); member->second.setter(c, *getRawPtr(g), val); } }; + template + naGhostType Ghost::_ghost_type; + } // namespace nasal +// Needs to be outside any namespace to make ADL work +/** + * Convert every shared pointer to a ghost. + */ +template +typename boost::enable_if< + nasal::internal::has_element_type< + typename nasal::internal::reduced_type::type + >, + naRef +>::type +to_nasal_helper(naContext c, T ptr) +{ + return nasal::Ghost::create(c, ptr); +} + +/** + * Convert nasal ghosts/hashes to shared pointer (of a ghost). + */ +template +typename boost::enable_if< + nasal::internal::has_element_type< + typename nasal::internal::reduced_type::type + >, + T +>::type +from_nasal_helper(naContext c, naRef ref, const T*) +{ + return nasal::Ghost::fromNasal(c, ref); +} + +/** + * Convert any pointer to a SGReference based object to a ghost. + */ +template +typename boost::enable_if, naRef>::type +to_nasal_helper(naContext c, T* ptr) +{ + return nasal::Ghost >::create(c, SGSharedPtr(ptr)); +} + +/** + * Convert nasal ghosts/hashes to pointer (of a SGReference based ghost). + */ +template +typename boost::enable_if< + boost::is_base_of::type>, + T +>::type +from_nasal_helper(naContext c, naRef ref, const T*) +{ + typedef SGSharedPtr::type> TypeRef; + return nasal::Ghost::fromNasal(c, ref).release(); +} + #endif /* SG_NASAL_GHOST_HXX_ */ diff -Nru simgear-2.10.0/simgear/nasal/cppbind/NasalCallContext.hxx simgear-3.0.0/simgear/nasal/cppbind/NasalCallContext.hxx --- simgear-2.10.0/simgear/nasal/cppbind/NasalCallContext.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/NasalCallContext.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,136 @@ +///@file +/// Call context for Nasal extension functions +/// +// Copyright (C) 2012 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_NASAL_CALL_CONTEXT_HXX_ +#define SG_NASAL_CALL_CONTEXT_HXX_ + +#include "from_nasal.hxx" +#include "to_nasal.hxx" + +namespace nasal +{ + + /** + * Context passed to a function/method being called from Nasal + */ + class CallContext + { + public: + CallContext(naContext c, size_t argc, naRef* args): + c(c), + argc(argc), + args(args) + {} + + bool isNumeric(size_t index) const + { + return (index < argc && naIsNum(args[index])); + } + + bool isString(size_t index) const + { + return (index < argc && naIsString(args[index])); + } + + bool isHash(size_t index) const + { + return (index < argc && naIsHash(args[index])); + } + + bool isVector(size_t index) const + { + return (index < argc && naIsVector(args[index])); + } + + bool isGhost(size_t index) const + { + return (index < argc && naIsGhost(args[index])); + } + + void popFront(size_t num = 1) + { + if( argc < num ) + return; + + args += num; + argc -= num; + } + + void popBack(size_t num = 1) + { + if( argc < num ) + return; + + argc -= num; + } + + /** + * Get the argument with given index if it exists. Otherwise returns the + * passed default value. + * + * @tparam T Type of argument (converted using ::from_nasal) + * @param index Index of requested argument + * @param def Default value returned if too few arguments available + */ + template + typename from_nasal_ptr::return_type + getArg(size_t index, const T& def = T()) const + { + if( index >= argc ) + return def; + + return from_nasal(args[index]); + } + + /** + * Get the argument with given index. Raises a Nasal runtime error if + * there are to few arguments available. + */ + template + typename from_nasal_ptr::return_type + requireArg(size_t index) const + { + if( index >= argc ) + naRuntimeError(c, "Missing required arg #%d", index); + + return from_nasal(args[index]); + } + + template + naRef to_nasal(T arg) const + { + return nasal::to_nasal(c, arg); + } + + template + typename from_nasal_ptr::return_type + from_nasal(naRef ref) const + { + return (*from_nasal_ptr::get())(c, ref); + } + + naContext c; + size_t argc; + naRef *args; + }; + +} // namespace nasal + + +#endif /* SG_NASAL_CALL_CONTEXT_HXX_ */ diff -Nru simgear-2.10.0/simgear/nasal/cppbind/NasalHash.hxx simgear-3.0.0/simgear/nasal/cppbind/NasalHash.hxx --- simgear-2.10.0/simgear/nasal/cppbind/NasalHash.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/NasalHash.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -87,6 +87,21 @@ } /** + * Get member converted to callable object + * + * @tparam Sig Function signature + * @param name Member name + */ + template + typename boost::enable_if< boost::is_function, + boost::function + >::type + get(const std::string& name) + { + return from_nasal_helper(_context, get(name), static_cast(0)); + } + + /** * Create a new child hash (module) * * @param name Name of the new hash inside this hash diff -Nru simgear-2.10.0/simgear/nasal/cppbind/NasalObjectHolder.cxx simgear-3.0.0/simgear/nasal/cppbind/NasalObjectHolder.cxx --- simgear-2.10.0/simgear/nasal/cppbind/NasalObjectHolder.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/NasalObjectHolder.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,51 @@ +// Wrapper class for keeping Nasal objects save from the garbage collector +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "NasalObjectHolder.hxx" +#include + +namespace nasal +{ + + //---------------------------------------------------------------------------- + ObjectHolder::~ObjectHolder() + { + naGCRelease(_gc_key); + } + + //---------------------------------------------------------------------------- + naRef ObjectHolder::get_naRef() const + { + return _ref; + } + + //---------------------------------------------------------------------------- + ObjectHolderRef ObjectHolder::makeShared(naRef obj) + { + return new ObjectHolder(obj); + } + + //---------------------------------------------------------------------------- + ObjectHolder::ObjectHolder(naRef obj): + _ref(obj), + _gc_key(naGCSave(obj)) + { + + } + +} // namespace nasal diff -Nru simgear-2.10.0/simgear/nasal/cppbind/NasalObjectHolder.hxx simgear-3.0.0/simgear/nasal/cppbind/NasalObjectHolder.hxx --- simgear-2.10.0/simgear/nasal/cppbind/NasalObjectHolder.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/NasalObjectHolder.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,69 @@ +///@file Wrapper class for keeping Nasal objects save from the garbage collector +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_NASAL_OBJECT_HOLDER_HXX_ +#define SG_NASAL_OBJECT_HOLDER_HXX_ + +#include +#include + +namespace nasal +{ + + class ObjectHolder; + typedef SGSharedPtr ObjectHolderRef; + + /** + * Prevent a Nasal object from being destroyed by the garbage collector during + * the lifetime of this object. + */ + class ObjectHolder: + public SGReferenced + { + public: + + /** + * + */ + ~ObjectHolder(); + + /** + * Get captured Nasal object + */ + naRef get_naRef() const; + + /** + * Save the given object as long as the returned holder exists. + * + * @param obj Object to save + */ + static ObjectHolderRef makeShared(naRef obj); + + protected: + naRef _ref; + int _gc_key; + + /** + * @param obj Object to save + */ + ObjectHolder(naRef obj); + }; + +} // namespace nasal + +#endif /* SG_NASAL_OBJECT_HOLDER_HXX_ */ diff -Nru simgear-2.10.0/simgear/nasal/cppbind/NasalString.cxx simgear-3.0.0/simgear/nasal/cppbind/NasalString.cxx --- simgear-2.10.0/simgear/nasal/cppbind/NasalString.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/NasalString.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,186 @@ +// Wrapper class for Nasal strings +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "NasalString.hxx" +#include "to_nasal.hxx" + +#include +#include +#include +#include +#include + +namespace nasal +{ + + /** + * Predicate (eg. for std::find_if) returning true if no character of the + * stored string given by the range [begin, end) matches. + */ + struct no_match: + public std::unary_function + { + no_match(const char* begin, const char* end): + _begin(begin), + _end(end) + {} + + bool operator()(const char c) const + { + return std::find(_begin, _end, c) == _end; + } + + private: + const char* _begin; + const char* _end; + }; + +//template +//Iterator +//rfind_first_of( Iterator rbegin_src, Iterator rend_src, +// Iterator begin_find, Iterator end_find ) +//{ +// for(; rbegin_src != rend_src; --rbegin_src) +// { +// for(Iterator chr = begin_find; chr != end_find; ++chr) +// { +// if( *rbegin_src == *chr ) +// return rbegin_src; +// } +// } +// return rend_src; +//} + + + const size_t String::npos = static_cast(-1); + + //---------------------------------------------------------------------------- + String::String(naContext c, const char* str): + _str( to_nasal(c, str) ) + { + assert( naIsString(_str) ); + } + + //---------------------------------------------------------------------------- + String::String(naRef str): + _str(str) + { + assert( naIsString(_str) ); + } + + //---------------------------------------------------------------------------- + const char* String::c_str() const + { + return naStr_data(_str); + } + + //---------------------------------------------------------------------------- + const char* String::begin() const + { + return c_str(); + } + + //---------------------------------------------------------------------------- + const char* String::end() const + { + return c_str() + size(); + } + + //---------------------------------------------------------------------------- + size_t String::size() const + { + return naStr_len(_str); + } + + //---------------------------------------------------------------------------- + size_t String::length() const + { + return size(); + } + + //---------------------------------------------------------------------------- + bool String::empty() const + { + return size() == 0; + } + + //---------------------------------------------------------------------------- + int String::compare(size_t pos, size_t len, const String& rhs) const + { + if( pos >= size() ) + throw std::out_of_range("nasal::String::compare: pos"); + + return memcmp( begin() + pos, + rhs.begin(), + std::min(rhs.size(), std::min(size() - pos, len)) ); + } + + //---------------------------------------------------------------------------- + bool String::starts_with(const String& rhs) const + { + return rhs.size() <= size() && compare(0, npos, rhs) == 0; + } + + //---------------------------------------------------------------------------- + bool String::ends_with(const String& rhs) const + { + return rhs.size() <= size() && compare(size() - rhs.size(), npos, rhs) == 0; + } + + //---------------------------------------------------------------------------- + size_t String::find(const char c, size_t pos) const + { + if( pos >= size() ) + return npos; + + const char* result = std::find(begin() + pos, end(), c); + + return result != end() ? result - begin() : npos; + } + + //---------------------------------------------------------------------------- + size_t String::find_first_of(const String& chr, size_t pos) const + { + if( pos >= size() ) + return npos; + + const char* result = std::find_first_of( begin() + pos, end(), + chr.begin(), chr.end() ); + + return result != end() ? result - begin() : npos; + } + + //---------------------------------------------------------------------------- + size_t String::find_first_not_of(const String& chr, size_t pos) const + { + if( pos >= size() ) + return npos; + + const char* result = std::find_if( begin() + pos, end(), + no_match(chr.begin(), chr.end()) ); + + return result != end() ? result - begin() : npos; + } + + //---------------------------------------------------------------------------- + const naRef String::get_naRef() const + { + return _str; + } + +} // namespace nasal diff -Nru simgear-2.10.0/simgear/nasal/cppbind/NasalString.hxx simgear-3.0.0/simgear/nasal/cppbind/NasalString.hxx --- simgear-2.10.0/simgear/nasal/cppbind/NasalString.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/NasalString.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,81 @@ +///@file Wrapper class for Nasal strings +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_NASAL_STRING_HXX_ +#define SG_NASAL_STRING_HXX_ + +#include "from_nasal.hxx" +#include "to_nasal.hxx" + +namespace nasal +{ + + /** + * A Nasal String + */ + class String + { + public: + + static const size_t npos; + + /** + * Create a new Nasal String + * + * @param c Nasal context for creating the string + * @param str String data + */ + String(naContext c, const char* str); + + /** + * Initialize from an existing Nasal String + * + * @param str Existing Nasal String + */ + String(naRef string); + + const char* c_str() const; + const char* begin() const; + const char* end() const; + + size_t size() const; + size_t length() const; + bool empty() const; + + int compare(size_t pos, size_t len, const String& rhs) const; + bool starts_with(const String& rhs) const; + bool ends_with(const String& rhs) const; + + size_t find(const char c, size_t pos = 0) const; + size_t find_first_of(const String& chr, size_t pos = 0) const; + size_t find_first_not_of(const String& chr, size_t pos = 0) const; + + /** + * Get Nasal representation of String + */ + const naRef get_naRef() const; + + protected: + + naRef _str; + + }; + +} // namespace nasal + +#endif /* SG_NASAL_STRING_HXX_ */ diff -Nru simgear-2.10.0/simgear/nasal/cppbind/nasal_traits.hxx simgear-3.0.0/simgear/nasal/cppbind/nasal_traits.hxx --- simgear-2.10.0/simgear/nasal/cppbind/nasal_traits.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/nasal_traits.hxx 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ -///@file -/// Type traits used for converting from and to Nasal types -/// -// Copyright (C) 2012 Thomas Geymayer -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - -#ifndef SG_NASAL_TRAITS_HXX_ -#define SG_NASAL_TRAITS_HXX_ - -#include - -namespace nasal -{ - template - struct is_vec2: public boost::integral_constant {}; - -#define SG_MAKE_TRAIT(templ,type,attr)\ - template templ\ - struct attr< type >:\ - public boost::integral_constant {}; - -#ifdef SGVec2_H - SG_MAKE_TRAIT(, SGVec2, is_vec2) -#endif - -#ifdef OSG_VEC2B - SG_MAKE_TRAIT(<>, osg::Vec2b, is_vec2) -#endif - -#ifdef OSG_VEC2D - SG_MAKE_TRAIT(<>, osg::Vec2d, is_vec2) -#endif - -#ifdef OSG_VEC2F - SG_MAKE_TRAIT(<>, osg::Vec2f, is_vec2) -#endif - -#ifdef OSG_VEC2S - SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2) -#endif - -#undef SG_MAKE_TRAIT - -} // namespace nasal -#endif /* SG_NASAL_TRAITS_HXX_ */ diff -Nru simgear-2.10.0/simgear/nasal/cppbind/to_nasal.cxx simgear-3.0.0/simgear/nasal/cppbind/to_nasal.cxx --- simgear-2.10.0/simgear/nasal/cppbind/to_nasal.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/to_nasal.cxx 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -// Conversion functions to convert C++ types to Nasal types -// -// Copyright (C) 2012 Thomas Geymayer -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - -#include "to_nasal.hxx" -#include "NasalHash.hxx" - -#include - -namespace nasal -{ - //---------------------------------------------------------------------------- - naRef to_nasal(naContext c, const std::string& str) - { - naRef ret = naNewString(c); - naStr_fromdata(ret, str.c_str(), str.size()); - return ret; - } - - //---------------------------------------------------------------------------- - naRef to_nasal(naContext c, const char* str) - { - return to_nasal(c, std::string(str)); - } - - //---------------------------------------------------------------------------- - naRef to_nasal(naContext c, naCFunction func) - { - return naNewFunc(c, naNewCCode(c, func)); - } - - //---------------------------------------------------------------------------- - naRef to_nasal(naContext c, const Hash& hash) - { - return hash.get_naRef(); - } - - //---------------------------------------------------------------------------- - naRef to_nasal(naContext c, naRef ref) - { - return ref; - } - - //---------------------------------------------------------------------------- - naRef to_nasal(naContext c, const SGPath& path) - { - return to_nasal(c, path.str()); - } -} // namespace nasal diff -Nru simgear-2.10.0/simgear/nasal/cppbind/to_nasal.hxx simgear-3.0.0/simgear/nasal/cppbind/to_nasal.hxx --- simgear-2.10.0/simgear/nasal/cppbind/to_nasal.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/cppbind/to_nasal.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -20,107 +20,52 @@ #ifndef SG_TO_NASAL_HXX_ #define SG_TO_NASAL_HXX_ -#include "nasal_traits.hxx" - -#include - -#include -#include - -#include -#include - -class SGPath; +#include namespace nasal { - class Hash; - - /** - * Convert std::string to Nasal string - */ - naRef to_nasal(naContext c, const std::string& str); - - /** - * Convert C-string to Nasal string - */ - // We need this to prevent the array overload of to_nasal being called - naRef to_nasal(naContext c, const char* str); - - /** - * Convert function pointer to Nasal function - */ - naRef to_nasal(naContext c, naCFunction func); - /** - * Convert a nasal::Hash to a Nasal hash - */ - naRef to_nasal(naContext c, const Hash& hash); - - /** - * Simple pass-through of naRef types to allow generic usage of to_nasal - */ - naRef to_nasal(naContext c, naRef ref); - - naRef to_nasal(naContext c, const SGPath& path); - - /** - * Convert a numeric type to Nasal number + * Convert any supported C++ type to Nasal. + * + * @param c Active Nasal context + * @param arg C++ Object to be converted + * @tparam T Type of converted object + * + * @throws bad_nasal_cast if conversion is not possible + * + * @note Every type which should be supported needs a function with the + * following signature declared (Type needs to be a const reference + * for non-integral types): + * + * naRef to_nasal_helper(naContext, Type) */ template - typename boost::enable_if< boost::is_arithmetic, naRef >::type - to_nasal(naContext c, T num) + naRef to_nasal(naContext c, T arg) { - return naNum(num); + return to_nasal_helper(c, arg); } - /** - * Convert a fixed size array to a Nasal vector - */ template naRef to_nasal(naContext c, const T(&array)[N]) { - naRef ret = naNewVector(c); - naVec_setsize(c, ret, N); - for(size_t i = 0; i < N; ++i) - naVec_set(ret, i, to_nasal(c, array[i])); - return ret; + return to_nasal_helper(c, array); } /** - * Convert std::vector to Nasal vector + * Wrapper to get pointer to specific version of to_nasal applicable to given + * type. */ - template< template class Vector, - class T, - class Alloc - > - typename boost::enable_if< boost::is_same< Vector, - std::vector - >, - naRef - >::type - to_nasal(naContext c, const Vector& vec) + template + struct to_nasal_ptr { - naRef ret = naNewVector(c); - naVec_setsize(c, ret, vec.size()); - for(size_t i = 0; i < vec.size(); ++i) - naVec_set(ret, i, to_nasal(c, vec[i])); - return ret; - } - - /** - * Convert a 2d vector to Nasal vector with 2 elements - */ - template - typename boost::enable_if, naRef>::type - to_nasal(naContext c, const Vec2& vec) - { - // We take just double because in Nasal every number is represented as - // double - double nasal_vec[2] = {vec[0], vec[1]}; - return to_nasal(c, nasal_vec); - } + typedef typename boost::call_traits::param_type param_type; + typedef naRef(*type)(naContext, param_type); + static type get() + { + return &to_nasal; + } + }; } // namespace nasal #endif /* SG_TO_NASAL_HXX_ */ diff -Nru simgear-2.10.0/simgear/nasal/data.h simgear-3.0.0/simgear/nasal/data.h --- simgear-2.10.0/simgear/nasal/data.h 2011-06-29 14:58:56.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/data.h 2014-02-15 00:04:11.000000000 +0000 @@ -96,7 +96,7 @@ #define MAX_STR_EMBLEN 15 struct naStr { GC_HEADER; - char emblen; /* [0-15], or -1 to indicate "not embedded" */ + signed char emblen; /* [0-15], or -1 to indicate "not embedded" */ unsigned int hashcode; union { unsigned char buf[16]; @@ -160,7 +160,15 @@ struct naCCode { GC_HEADER; - naCFunction fptr; + union { + naCFunction fptr; //save); + mark(globals->save_hash); mark(globals->symbols); mark(globals->meRef); mark(globals->argRef); @@ -118,6 +119,15 @@ } } +void naGC() +{ + LOCK(); + globals->needGC = 1; + bottleneck(); + UNLOCK(); + naCheckBottleneck(); +} + void naCheckBottleneck() { if(globals->bottleneck) { LOCK(); bottleneck(); UNLOCK(); } @@ -128,6 +138,12 @@ naFree(o->constants); o->constants = 0; } +static void naCCode_gcclean(struct naCCode* c) +{ + if(c->fptru && c->user_data && c->destroy) c->destroy(c->user_data); + c->user_data = 0; +} + static void naGhost_gcclean(struct naGhost* g) { if(g->ptr && g->gtype->destroy) g->gtype->destroy(g->ptr); @@ -142,6 +158,7 @@ case T_VEC: naVec_gcclean ((struct naVec*) o); break; case T_HASH: naiGCHashClean ((struct naHash*) o); break; case T_CODE: naCode_gcclean ((struct naCode*) o); break; + case T_CCODE: naCCode_gcclean((struct naCCode*)o); break; case T_GHOST: naGhost_gcclean((struct naGhost*)o); break; } p->free[p->nfree++] = o; // ...and add it to the free list diff -Nru simgear-2.10.0/simgear/nasal/lex.c simgear-3.0.0/simgear/nasal/lex.c --- simgear-2.10.0/simgear/nasal/lex.c 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/lex.c 2014-02-15 00:04:11.000000000 +0000 @@ -134,7 +134,8 @@ tok->prev = last; tok->children = 0; tok->lastChild = 0; - + tok->rule = 0; + // Context sensitivity hack: a "-" following a binary operator of // equal or higher precedence must be a unary negation. Needed to // get precedence right in the parser for expressiong like "a * -2" diff -Nru simgear-2.10.0/simgear/nasal/lib.c simgear-3.0.0/simgear/nasal/lib.c --- simgear-2.10.0/simgear/nasal/lib.c 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/lib.c 2014-02-15 00:04:11.000000000 +0000 @@ -146,6 +146,32 @@ return naStr_substr(naNewString(c), src, start, len); } +static naRef f_left(naContext c, naRef me, int argc, naRef* args) +{ + int len; + naRef src = argc > 0 ? args[0] : naNil(); + naRef lenr = argc > 1 ? naNumValue(args[1]) : naNil(); + if(!naIsString(src)) ARGERR(); + if(!naIsNum(lenr)) ARGERR(); + len = (int)lenr.num; + if(len < 0) len = 0; + return naStr_substr(naNewString(c), src, 0, len); +} + +static naRef f_right(naContext c, naRef me, int argc, naRef* args) +{ + int len, srclen; + naRef src = argc > 0 ? args[0] : naNil(); + naRef lenr = argc > 1 ? naNumValue(args[1]) : naNil(); + if(!naIsString(src)) ARGERR(); + if(!naIsNum(lenr)) ARGERR(); + srclen = naStr_len(src); + len = (int)lenr.num; + if (len > srclen) len = srclen; + if(len < 0) len = 0; + return naStr_substr(naNewString(c), src, srclen - len, len); +} + static naRef f_chr(naContext c, naRef me, int argc, naRef* args) { char chr[1]; @@ -573,6 +599,8 @@ { "streq", f_streq }, { "cmp", f_cmp }, { "substr", f_substr }, + { "left", f_left }, + { "right", f_right }, { "chr", f_chr }, { "contains", f_contains }, { "typeof", f_typeof }, diff -Nru simgear-2.10.0/simgear/nasal/mathlib.c simgear-3.0.0/simgear/nasal/mathlib.c --- simgear-2.10.0/simgear/nasal/mathlib.c 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/mathlib.c 2014-02-15 00:04:11.000000000 +0000 @@ -65,6 +65,16 @@ return VALIDATE(a); } +static naRef f_pow(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + naRef b = naNumValue(argc > 1 ? args[1] : naNil()); + if(naIsNil(a) || naIsNil(b)) + naRuntimeError(c, "non numeric argument to pow()"); + a.num = pow(a.num, b.num); + return VALIDATE(a); +} + static naRef f_atan2(naContext c, naRef me, int argc, naRef* args) { naRef a = naNumValue(argc > 0 ? args[0] : naNil()); @@ -75,16 +85,146 @@ return VALIDATE(a); } +static naRef f_floor(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + if(naIsNil(a)) + naRuntimeError(c, "non numeric argument to floor()"); + a.num = floor(a.num); + return VALIDATE(a); +} + +static naRef f_ceil(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + if(naIsNil(a)) + naRuntimeError(c, "non numeric argument to ceil()"); + a.num = ceil(a.num); + return VALIDATE(a); +} + +static naRef f_fmod(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + naRef b = naNumValue(argc > 1 ? args[1] : naNil()); + if(naIsNil(a) || naIsNil(b)) + naRuntimeError(c, "non numeric arguments to fmod()"); + + a.num = fmod(a.num, b.num); + return VALIDATE(a); +} + +static naRef f_clamp(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + naRef b = naNumValue(argc > 1 ? args[1] : naNil()); + naRef x = naNumValue(argc > 2 ? args[2] : naNil()); + + if(naIsNil(a) || naIsNil(b) || naIsNil(x)) + naRuntimeError(c, "non numeric arguments to clamp()"); + + if (a.num < b.num) b.num = a.num; + if (b.num > x.num) b.num = x.num; + return VALIDATE(b); +} + +static naRef f_periodic(naContext c, naRef me, int argc, naRef* args) +{ + double range; + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + naRef b = naNumValue(argc > 1 ? args[1] : naNil()); + naRef x = naNumValue(argc > 2 ? args[2] : naNil()); + + if(naIsNil(a) || naIsNil(b) || naIsNil(x)) + naRuntimeError(c, "non numeric arguments to periodic()"); + + range = b.num - a.num; + x.num = x.num - range*floor((x.num - a.num)/range); + // two security checks that can only happen due to roundoff + if (x.num <= a.num) + x.num = a.num; + if (b.num <= x.num) + x.num = b.num; + return VALIDATE(x); + +// x.num = SGMiscd::normalizePeriodic(a, b, x); + return VALIDATE(x); +} + +static naRef f_round(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + naRef b = naNumValue(argc > 1 ? args[1] : naNil()); +#ifdef _MSC_VER + double x,y; +#endif + if(naIsNil(a)) + naRuntimeError(c, "non numeric arguments to round()"); + if (naIsNil(b)) + b.num = 1.0; + +#ifdef _MSC_VER // MSVC is not C99-compatible, no round() in math.h + y = a.num / b.num; + x = floor(y + 0.5); +#else + double x = round(a.num / b.num); +#endif + a.num = x * b.num; + + return VALIDATE(a); +} + + +static naRef f_tan(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + if(naIsNil(a)) + naRuntimeError(c, "non numeric arguments to tan()"); + + a.num = tan(a.num); + return VALIDATE(a); +} + +static naRef f_asin(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + if(naIsNil(a)) + naRuntimeError(c, "non numeric argument to asin()"); + a.num = asin(a.num); + return VALIDATE(a); +} + +static naRef f_acos(naContext c, naRef me, int argc, naRef* args) +{ + naRef a = naNumValue(argc > 0 ? args[0] : naNil()); + if(naIsNil(a)) + naRuntimeError(c, "non numeric argument to acos()"); + a.num = acos(a.num); + return VALIDATE(a); +} + static naCFuncItem funcs[] = { { "sin", f_sin }, { "cos", f_cos }, { "exp", f_exp }, { "ln", f_ln }, + { "pow", f_pow }, { "sqrt", f_sqrt }, { "atan2", f_atan2 }, + { "floor", f_floor }, + { "ceil", f_ceil }, + { "fmod", f_fmod }, + { "clamp", f_clamp }, + { "periodic", f_periodic }, + { "round", f_round }, + { "tan", f_tan }, + { "acos", f_acos }, + { "asin", f_asin }, { 0 } }; + + naRef naInit_math(naContext c) { naRef ns = naGenLib(c, funcs); diff -Nru simgear-2.10.0/simgear/nasal/misc.c simgear-3.0.0/simgear/nasal/misc.c --- simgear-2.10.0/simgear/nasal/misc.c 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/misc.c 2014-02-15 00:04:11.000000000 +0000 @@ -107,6 +107,24 @@ { naRef r = naNew(c, T_CCODE); PTR(r).ccode->fptr = fptr; + PTR(r).ccode->fptru = 0; + return r; +} + +naRef naNewCCodeU(struct Context* c, naCFunctionU fptr, void* user_data) +{ + return naNewCCodeUD(c, fptr, user_data, 0); +} + +naRef naNewCCodeUD( struct Context* c, + naCFunctionU fptr, + void* user_data, + void (*destroy)(void*) ) +{ + naRef r = naNew(c, T_CCODE); + PTR(r).ccode->fptru = fptr; + PTR(r).ccode->user_data = user_data; + PTR(r).ccode->destroy = destroy; return r; } diff -Nru simgear-2.10.0/simgear/nasal/nasal.h simgear-3.0.0/simgear/nasal/nasal.h --- simgear-2.10.0/simgear/nasal/nasal.h 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/nasal.h 2014-02-15 00:04:11.000000000 +0000 @@ -16,10 +16,14 @@ #endif typedef struct Context* naContext; - + // The function signature for an extension function: typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args); +// The function signature for an extension function with userdata passed back: +typedef naRef (*naCFunctionU) + (naContext ctx, naRef me, int argc, naRef* args, void* user_data); + // All Nasal code runs under the watch of a naContext: naContext naNewContext(); void naFreeContext(naContext c); @@ -38,10 +42,25 @@ void naSetUserData(naContext c, void* p); void* naGetUserData(naContext c) GCC_PURE; +// run GC now (may block) +void naGC(); + // "Save" this object in the context, preventing it (and objects // referenced by it) from being garbage collected. +// TODO do we need a context? It is not used anyhow... void naSave(naContext ctx, naRef obj); +// "Save" this object and get a key which allows do mark the object as free +// later on (with naGCFree). +int naGCSave(naRef obj); + +// Release an object previously passed to naGCSave to allow it being cleaned up +// by the garbage collector. +void naGCRelease(int key); + +// Drop all saved references +void naClearSaved(); + // Similar, but the object is automatically released when the // context next runs native bytecode. Useful for saving off C-space // temporaries to protect them before passing back into a naCall. @@ -84,6 +103,28 @@ // naModUnlock() first if the lock is already held. naRef naContinue(naContext ctx); +// Does a naCall() in a given context. Wrapped here to make lock +// tracking easier. Extension functions are called with the lock, but +// we have to release it before making a new naCall(). So rather than +// drop the lock in every extension function that might call back into +// Nasal, we keep a stack depth counter here and only unlock/lock +// around the naCall if it isn't the first one. +naRef naCallMethodCtx( naContext ctx, + naRef code, + naRef self, + int argc, + naRef* args, + naRef locals ); + +// Same as naCallMethodCtx but creates (and afterwards destroyes) a new context +naRef naCallMethod(naRef code, naRef self, int argc, naRef* args, naRef locals); + +typedef void (*naErrorHandler)(naContext); + +// Register a handler to be called if an error is raised during the execution of +// naCallMethodCtx or naCallMethod. +naErrorHandler naSetErrorHandler(naErrorHandler cb); + // Throw an error from the current call stack. This function makes a // longjmp call to a handler in naCall() and DOES NOT RETURN. It is // intended for use in library code that cannot otherwise report an @@ -119,6 +160,9 @@ naRef naInit_gtk(naContext ctx); naRef naInit_cairo(naContext ctx); +// Returns a hash which can be used to add methods callable on strings +naRef naInit_string(naContext c); + // Context stack inspection, frame zero is the "top" int naStackDepth(naContext ctx); int naGetLine(naContext ctx, int frame); @@ -143,7 +187,19 @@ naRef naNewVector(naContext c); naRef naNewHash(naContext c); naRef naNewFunc(naContext c, naRef code); + +/** + * Register extension function + * + * @param fptr Pointer to C-function + * @param user_data Optional user data passed back on calling the function + * @param destroy Optional callback called if function gets freed by garbage + * collector to free user data if required. + */ naRef naNewCCode(naContext c, naCFunction fptr); +naRef naNewCCodeU(naContext c, naCFunctionU fptr, void* user_data); +naRef naNewCCodeUD(naContext c, naCFunctionU fptr, void* user_data, + void (*destroy)(void*)); // Some useful conversion/comparison routines int naEqual(naRef a, naRef b) GCC_PURE; @@ -159,15 +215,34 @@ naRef naStr_concat(naRef dest, naRef s1, naRef s2); naRef naStr_substr(naRef dest, naRef str, int start, int len); naRef naInternSymbol(naRef sym); +naRef getStringMethods(naContext c); // Vector utilities: int naVec_size(naRef v); naRef naVec_get(naRef v, int i); void naVec_set(naRef vec, int i, naRef o); int naVec_append(naRef vec, naRef o); -naRef naVec_removelast(naRef vec); void naVec_setsize(naContext c, naRef vec, int sz); +/** + * Remove and retrieve the first element of the vector. + * + * This operation reduces the size of the vector by one and moves all elements + * by one towards the begin of the vector. + * + * @return The element removed from the begin + */ +naRef naVec_removefirst(naRef vec); + +/** + * Remove and retrieve the last element of the vector. + * + * This operation reduces the size of the vector by one. + * + * @return The element removed from the end + */ +naRef naVec_removelast(naRef vec); + // Hash utilities: int naHash_size(naRef h); int naHash_get(naRef hash, naRef key, naRef* out); diff -Nru simgear-2.10.0/simgear/nasal/string.c simgear-3.0.0/simgear/nasal/string.c --- simgear-2.10.0/simgear/nasal/string.c 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/string.c 2014-02-15 00:04:11.000000000 +0000 @@ -320,3 +320,27 @@ *ptr = 0; return ptr - s; } + + +//------------------------------------------------------------------------------ +static naRef string_methods; +static int init = 0; // As we can't use naNil() for static initialization we + // need a separate variable for saving whether we have + // already initialized. + +//------------------------------------------------------------------------------ +naRef naInit_string(naContext c) +{ + string_methods = naNewHash(c); + init = 1; + return string_methods; +} + +//------------------------------------------------------------------------------ +naRef getStringMethods(naContext c) +{ + if( !init ) + return naNil(); + + return string_methods; +} diff -Nru simgear-2.10.0/simgear/nasal/vector.c simgear-3.0.0/simgear/nasal/vector.c --- simgear-2.10.0/simgear/nasal/vector.c 2012-01-17 20:33:53.000000000 +0000 +++ simgear-3.0.0/simgear/nasal/vector.c 2014-02-15 00:04:11.000000000 +0000 @@ -69,6 +69,7 @@ return 0; } +//------------------------------------------------------------------------------ void naVec_setsize(naContext c, naRef vec, int sz) { if (sz < 0) @@ -86,6 +87,26 @@ } } +//------------------------------------------------------------------------------ +naRef naVec_removefirst(naRef vec) +{ + naRef o; + int i; + if(IS_VEC(vec)) { + struct VecRec* v = PTR(vec).vec->rec; + if(!v || v->size == 0) return naNil(); + o = v->array[0]; + for (i=1; isize; i++) + v->array[i-1] = v->array[i]; + v->size--; + if(v->size < (v->alloced >> 1)) + resize(PTR(vec).vec); + return o; + } + return naNil(); +} + +//------------------------------------------------------------------------------ naRef naVec_removelast(naRef vec) { naRef o; diff -Nru simgear-2.10.0/simgear/package/Catalog.cxx simgear-3.0.0/simgear/package/Catalog.cxx --- simgear-2.10.0/simgear/package/Catalog.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/Catalog.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,314 @@ +// Copyright (C) 2013 James Turner - zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace simgear { + +namespace pkg { + +CatalogList static_catalogs; + +////////////////////////////////////////////////////////////////////////////// + +class Catalog::Downloader : public HTTP::Request +{ +public: + Downloader(Catalog* aOwner, const std::string& aUrl) : + HTTP::Request(aUrl), + m_owner(aOwner) + { + } + +protected: + virtual void gotBodyData(const char* s, int n) + { + m_buffer += std::string(s, n); + } + + virtual void onDone() + { + if (responseCode() != 200) { + SG_LOG(SG_GENERAL, SG_ALERT, "catalog download failure:" << m_owner->url()); + m_owner->refreshComplete(Delegate::FAIL_DOWNLOAD); + return; + } + + SGPropertyNode* props = new SGPropertyNode; + + try { + readProperties(m_buffer.data(), m_buffer.size(), props); + m_owner->parseProps(props); + } catch (sg_exception& e) { + SG_LOG(SG_GENERAL, SG_ALERT, "catalog parse failure:" << m_owner->url()); + m_owner->refreshComplete(Delegate::FAIL_EXTRACT); + return; + } + + std::string ver(m_owner->root()->catalogVersion()); + if (!checkVersion(ver, props)) { + SG_LOG(SG_GENERAL, SG_WARN, "downloaded catalog " << m_owner->url() << ", version mismatch:\n\t" + << props->getStringValue("version") << " vs required " << ver); + m_owner->refreshComplete(Delegate::FAIL_VERSION); + return; + } + + // cache the catalog data, now we have a valid install root + Dir d(m_owner->installRoot()); + SGPath p = d.file("catalog.xml"); + + std::ofstream f(p.c_str(), std::ios::out | std::ios::trunc); + f.write(m_buffer.data(), m_buffer.size()); + f.close(); + + time(&m_owner->m_retrievedTime); + m_owner->writeTimestamp(); + m_owner->refreshComplete(Delegate::FAIL_SUCCESS); + } + +private: + bool checkVersion(const std::string& aVersion, SGPropertyNode* aProps) + { + BOOST_FOREACH(SGPropertyNode* v, aProps->getChildren("version")) { + if (v->getStringValue() == aVersion) { + return true; + } + } + return false; + } + + Catalog* m_owner; + std::string m_buffer; +}; + +////////////////////////////////////////////////////////////////////////////// + +CatalogList Catalog::allCatalogs() +{ + return static_catalogs; +} + +Catalog::Catalog(Root *aRoot) : + m_root(aRoot), + m_retrievedTime(0) +{ + static_catalogs.push_back(this); +} + +Catalog::~Catalog() +{ + CatalogList::iterator it = std::find(static_catalogs.begin(), static_catalogs.end(), this); + static_catalogs.erase(it); +} + +Catalog* Catalog::createFromUrl(Root* aRoot, const std::string& aUrl) +{ + Catalog* c = new Catalog(aRoot); + Downloader* dl = new Downloader(c, aUrl); + aRoot->makeHTTPRequest(dl); + + return c; +} + +Catalog* Catalog::createFromPath(Root* aRoot, const SGPath& aPath) +{ + SGPath xml = aPath; + xml.append("catalog.xml"); + if (!xml.exists()) { + return NULL; + } + + SGPropertyNode_ptr props; + try { + props = new SGPropertyNode; + readProperties(xml.str(), props); + } catch (sg_exception& e) { + return NULL; + } + + if (props->getStringValue("version") != aRoot->catalogVersion()) { + SG_LOG(SG_GENERAL, SG_WARN, "skipping catalog at " << aPath << ", version mismatch:\n\t" + << props->getStringValue("version") << " vs required " << aRoot->catalogVersion()); + return NULL; + } + + Catalog* c = new Catalog(aRoot); + c->m_installRoot = aPath; + c->parseProps(props); + c->parseTimestamp(); + + return c; +} + +PackageList +Catalog::packagesMatching(const SGPropertyNode* aFilter) const +{ + PackageList r; + BOOST_FOREACH(Package* p, m_packages) { + if (p->matches(aFilter)) { + r.push_back(p); + } + } + return r; +} + +PackageList +Catalog::packagesNeedingUpdate() const +{ + PackageList r; + BOOST_FOREACH(Package* p, m_packages) { + if (!p->isInstalled()) { + continue; + } + + if (p->install()->hasUpdate()) { + r.push_back(p); + } + } + return r; +} + +void Catalog::refresh() +{ + Downloader* dl = new Downloader(this, url()); + m_root->makeHTTPRequest(dl); + m_root->catalogRefreshBegin(this); +} + +void Catalog::parseProps(const SGPropertyNode* aProps) +{ + // copy everything except package children? + m_props = new SGPropertyNode; + + int nChildren = aProps->nChildren(); + for (int i = 0; i < nChildren; i++) { + const SGPropertyNode* pkgProps = aProps->getChild(i); + if (strcmp(pkgProps->getName(), "package") == 0) { + Package* p = new Package(pkgProps, this); + m_packages.push_back(p); + } else { + SGPropertyNode* c = m_props->getChild(pkgProps->getName(), pkgProps->getIndex(), true); + copyProperties(pkgProps, c); + } + } // of children iteration + + if (m_installRoot.isNull()) { + m_installRoot = m_root->path(); + m_installRoot.append(id()); + + Dir d(m_installRoot); + d.create(0755); + } +} + +Package* Catalog::getPackageById(const std::string& aId) const +{ + BOOST_FOREACH(Package* p, m_packages) { + if (p->id() == aId) { + return p; + } + } + + return NULL; // not found +} + +std::string Catalog::id() const +{ + return m_props->getStringValue("id"); +} + +std::string Catalog::url() const +{ + return m_props->getStringValue("url"); +} + +std::string Catalog::description() const +{ + return getLocalisedString(m_props, "description"); +} + +SGPropertyNode* Catalog::properties() const +{ + return m_props.ptr(); +} + +void Catalog::parseTimestamp() +{ + SGPath timestampFile = m_installRoot; + timestampFile.append(".timestamp"); + std::ifstream f(timestampFile.c_str(), std::ios::in); + f >> m_retrievedTime; +} + +void Catalog::writeTimestamp() +{ + SGPath timestampFile = m_installRoot; + timestampFile.append(".timestamp"); + std::ofstream f(timestampFile.c_str(), std::ios::out | std::ios::trunc); + f << m_retrievedTime << std::endl; +} + +unsigned int Catalog::ageInSeconds() const +{ + time_t now; + time(&now); + int diff = ::difftime(now, m_retrievedTime); + return (diff < 0) ? 0 : diff; +} + +bool Catalog::needsRefresh() const +{ + unsigned int maxAge = m_props->getIntValue("max-age-sec", m_root->maxAgeSeconds()); + return (ageInSeconds() > maxAge); +} + +std::string Catalog::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const +{ + if (aRoot->hasChild(m_root->getLocale())) { + const SGPropertyNode* localeRoot = aRoot->getChild(m_root->getLocale().c_str()); + if (localeRoot->hasChild(aName)) { + return localeRoot->getStringValue(aName); + } + } + + return aRoot->getStringValue(aName); +} + +void Catalog::refreshComplete(Delegate::FailureCode aReason) +{ + m_root->catalogRefreshComplete(this, aReason); +} + + +} // of namespace pkg + +} // of namespace simgear diff -Nru simgear-2.10.0/simgear/package/Catalog.hxx simgear-3.0.0/simgear/package/Catalog.hxx --- simgear-2.10.0/simgear/package/Catalog.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/Catalog.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,125 @@ +// Copyright (C) 2013 James Turner - zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef SG_PACKAGE_CATALOG_HXX +#define SG_PACKAGE_CATALOG_HXX + +#include +#include + +#include +#include + +#include + +namespace simgear +{ + +namespace HTTP { class Client; } + +namespace pkg +{ + +// forward decls +class Package; +class Catalog; +class Root; + +typedef std::vector PackageList; +typedef std::vector CatalogList; + +class Catalog +{ +public: + virtual ~Catalog(); + + static Catalog* createFromUrl(Root* aRoot, const std::string& aUrl); + + static Catalog* createFromPath(Root* aRoot, const SGPath& aPath); + + static CatalogList allCatalogs(); + + Root* root() const + { return m_root;}; + + /** + * perform a refresh of the catalog contents + */ + void refresh(); + /** + * retrieve packages in this catalog matching a filter. + * filter consists of required / minimum values, AND-ed together. + */ + PackageList packagesMatching(const SGPropertyNode* aFilter) const; + + /** + * retrieve all the packages in the catalog which are installed + * and have a pendig update + */ + PackageList packagesNeedingUpdate() const; + + SGPath installRoot() const + { return m_installRoot; } + + std::string id() const; + + std::string url() const; + + std::string description() const; + + Package* getPackageById(const std::string& aId) const; + + /** + * test if the catalog data was retrieved longer ago than the + * maximum permitted age for this catalog. + */ + bool needsRefresh() const; + + unsigned int ageInSeconds() const; + + /** + * access the raw property data in the catalog + */ + SGPropertyNode* properties() const; +private: + Catalog(Root* aRoot); + + class Downloader; + friend class Downloader; + + void parseProps(const SGPropertyNode* aProps); + + void refreshComplete(Delegate::FailureCode aReason); + + void parseTimestamp(); + void writeTimestamp(); + + std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const; + + Root* m_root; + SGPropertyNode_ptr m_props; + SGPath m_installRoot; + + PackageList m_packages; + time_t m_retrievedTime; +}; + +} // of namespace pkg + +} // of namespace simgear + +#endif // of SG_PACKAGE_CATALOG_HXX diff -Nru simgear-2.10.0/simgear/package/CMakeLists.txt simgear-3.0.0/simgear/package/CMakeLists.txt --- simgear-2.10.0/simgear/package/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,28 @@ + +include (SimGearComponent) + +set(HEADERS + Catalog.hxx + Package.hxx + Install.hxx + Root.hxx + Delegate.hxx + ) + +set(SOURCES + Catalog.cxx + Package.cxx + Install.cxx + Root.cxx +# internal helpers + md5.c md5.h + ioapi.c ioapi_mem.c ioapi.h + unzip.h unzip.c + ) + +simgear_component(package package "${SOURCES}" "${HEADERS}") + +if(ENABLE_PKGUTIL) + add_executable(sg_pkgutil pkgutil.cxx) + target_link_libraries(sg_pkgutil ${TEST_LIBS}) +endif() diff -Nru simgear-2.10.0/simgear/package/Delegate.hxx simgear-3.0.0/simgear/package/Delegate.hxx --- simgear-2.10.0/simgear/package/Delegate.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/Delegate.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,75 @@ +// Copyright (C) 2013 James Turner - zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef SG_PACKAGE_DELEGATE_HXX +#define SG_PACKAGE_DELEGATE_HXX + +namespace simgear +{ + +namespace pkg +{ + +class Install; +class Catalog; + +/** + * package delegate is the mechanism to discover progress / completion / + * errors in packaging steps asynchronously. + */ +class Delegate +{ +public: + typedef enum { + FAIL_SUCCESS = 0, ///< not a failure :) + FAIL_UNKNOWN = 1, + FAIL_CHECKSUM, ///< package MD5 verificstion failed + FAIL_DOWNLOAD, ///< network issue + FAIL_EXTRACT, ///< package archive failed to extract cleanly + FAIL_FILESYSTEM, ///< unknown filesystem error occurred + FAIL_VERSION ///< version check mismatch + } FailureCode; + + + virtual ~Delegate() { } + + /** + * invoked when all catalogs have finished refreshing - either successfully + * or with a failure. + */ + virtual void refreshComplete() = 0; + + /** + * emitted when a catalog fails to refresh, due to a network issue or + * some other failure. + */ + virtual void failedRefresh(Catalog*, FailureCode aReason) = 0; + + virtual void startInstall(Install* aInstall) = 0; + virtual void installProgress(Install* aInstall, unsigned int aBytes, unsigned int aTotal) = 0; + virtual void finishInstall(Install* aInstall) = 0; + + + virtual void failedInstall(Install* aInstall, FailureCode aReason) = 0; + +}; + +} // of namespace pkg + +} // of namespace simgear + +#endif // of SG_PACKAGE_DELEGATE_HXX diff -Nru simgear-2.10.0/simgear/package/Install.cxx simgear-3.0.0/simgear/package/Install.cxx --- simgear-2.10.0/simgear/package/Install.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/Install.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,338 @@ +// Copyright (C) 2013 James Turner - zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +extern "C" { + void fill_memory_filefunc (zlib_filefunc_def*); +} + +namespace simgear { + +namespace pkg { + +class Install::PackageArchiveDownloader : public HTTP::Request +{ +public: + PackageArchiveDownloader(Install* aOwner) : + HTTP::Request("" /* dummy URL */), + m_owner(aOwner) + { + m_urls = m_owner->package()->downloadUrls(); + if (m_urls.empty()) { + throw sg_exception("no package download URLs"); + } + + // TODO randomise order of m_urls + + m_extractPath = aOwner->path().dir(); + m_extractPath.append("_DOWNLOAD"); // add some temporary value + + } + +protected: + virtual std::string url() const + { + return m_urls.front(); + } + + virtual void responseHeadersComplete() + { + Dir d(m_extractPath); + d.create(0755); + + memset(&m_md5, 0, sizeof(SG_MD5_CTX)); + SG_MD5Init(&m_md5); + } + + virtual void gotBodyData(const char* s, int n) + { + m_buffer += std::string(s, n); + SG_MD5Update(&m_md5, (unsigned char*) s, n); + + m_owner->installProgress(m_buffer.size(), responseLength()); + } + + virtual void onDone() + { + if (responseCode() != 200) { + SG_LOG(SG_GENERAL, SG_ALERT, "download failure"); + doFailure(Delegate::FAIL_DOWNLOAD); + return; + } + + unsigned char digest[MD5_DIGEST_LENGTH]; + SG_MD5Final(digest, &m_md5); + // convert final sum to hex + const char hexChar[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + std::stringstream hexMd5; + for (int i=0; i> 4]; + hexMd5 << hexChar[digest[i] & 0x0f]; + } + + if (hexMd5.str() != m_owner->package()->md5()) { + SG_LOG(SG_GENERAL, SG_ALERT, "md5 verification failed:\n" + << "\t" << hexMd5.str() << "\n\t" + << m_owner->package()->md5() << "\n\t" + << "downloading from:" << url()); + doFailure(Delegate::FAIL_CHECKSUM); + return; + } + + if (!extractUnzip()) { + SG_LOG(SG_GENERAL, SG_WARN, "zip extraction failed"); + doFailure(Delegate::FAIL_EXTRACT); + return; + } + + if (m_owner->path().exists()) { + //std::cout << "removing existing path" << std::endl; + Dir destDir(m_owner->path()); + destDir.remove(true /* recursive */); + } + + m_extractPath.append(m_owner->package()->id()); + bool ok = m_extractPath.rename(m_owner->path()); + if (!ok) { + doFailure(Delegate::FAIL_FILESYSTEM); + return; + } + + m_owner->m_revision = m_owner->package()->revision(); + m_owner->writeRevisionFile(); + m_owner->installResult(Delegate::FAIL_SUCCESS); + } + +private: + + void extractCurrentFile(unzFile zip, char* buffer, size_t bufferSize) + { + unz_file_info fileInfo; + unzGetCurrentFileInfo(zip, &fileInfo, + buffer, bufferSize, + NULL, 0, /* extra field */ + NULL, 0 /* comment field */); + + std::string name(buffer); + // no absolute paths, no 'up' traversals + // we could also look for suspicious file extensions here (forbid .dll, .exe, .so) + if ((name[0] == '/') || (name.find("../") != std::string::npos) || (name.find("..\\") != std::string::npos)) { + throw sg_format_exception("Bad zip path", name); + } + + if (fileInfo.uncompressed_size == 0) { + // assume it's a directory for now + // since we create parent directories when extracting + // a path, we're done here + return; + } + + int result = unzOpenCurrentFile(zip); + if (result != UNZ_OK) { + throw sg_io_exception("opening current zip file failed", sg_location(name)); + } + + std::ofstream outFile; + bool eof = false; + SGPath path(m_extractPath); + path.append(name); + + // create enclosing directory heirarchy as required + Dir parentDir(path.dir()); + if (!parentDir.exists()) { + bool ok = parentDir.create(0755); + if (!ok) { + throw sg_io_exception("failed to create directory heirarchy for extraction", path.c_str()); + } + } + + outFile.open(path.c_str(), std::ios::binary | std::ios::trunc | std::ios::out); + if (outFile.fail()) { + throw sg_io_exception("failed to open output file for writing", path.c_str()); + } + + while (!eof) { + int bytes = unzReadCurrentFile(zip, buffer, bufferSize); + if (bytes < 0) { + throw sg_io_exception("unzip failure reading curent archive", sg_location(name)); + } else if (bytes == 0) { + eof = true; + } else { + outFile.write(buffer, bytes); + } + } + + outFile.close(); + unzCloseCurrentFile(zip); + } + + bool extractUnzip() + { + bool result = true; + zlib_filefunc_def memoryAccessFuncs; + fill_memory_filefunc(&memoryAccessFuncs); + + char bufferName[128]; + snprintf(bufferName, 128, "%p+%lx", m_buffer.data(), m_buffer.size()); + unzFile zip = unzOpen2(bufferName, &memoryAccessFuncs); + + const size_t BUFFER_SIZE = 32 * 1024; + void* buf = malloc(BUFFER_SIZE); + + try { + int result = unzGoToFirstFile(zip); + if (result != UNZ_OK) { + throw sg_exception("failed to go to first file in archive"); + } + + while (true) { + extractCurrentFile(zip, (char*) buf, BUFFER_SIZE); + result = unzGoToNextFile(zip); + if (result == UNZ_END_OF_LIST_OF_FILE) { + break; + } else if (result != UNZ_OK) { + throw sg_io_exception("failed to go to next file in the archive"); + } + } + } catch (sg_exception& e) { + result = false; + } + + free(buf); + unzClose(zip); + return result; + } + + void doFailure(Delegate::FailureCode aReason) + { + Dir dir(m_extractPath); + dir.remove(true /* recursive */); + + if (m_urls.size() == 1) { + std::cout << "failure:" << aReason << std::endl; + m_owner->installResult(aReason); + return; + } + + std::cout << "retrying download" << std::endl; + m_urls.erase(m_urls.begin()); // pop first URL + } + + Install* m_owner; + string_list m_urls; + SG_MD5_CTX m_md5; + std::string m_buffer; + SGPath m_extractPath; +}; + +//////////////////////////////////////////////////////////////////// + +Install::Install(Package* aPkg, const SGPath& aPath) : + m_package(aPkg), + m_path(aPath), + m_download(NULL) +{ + parseRevision(); +} + +Install* Install::createFromPath(const SGPath& aPath, Catalog* aCat) +{ + std::string id = aPath.file(); + Package* pkg = aCat->getPackageById(id); + if (!pkg) + throw sg_exception("no package with id:" + id); + + return new Install(pkg, aPath); +} + +void Install::parseRevision() +{ + SGPath revisionFile = m_path; + revisionFile.append(".revision"); + if (!revisionFile.exists()) { + m_revision = 0; + return; + } + + std::ifstream f(revisionFile.c_str(), std::ios::in); + f >> m_revision; +} + +void Install::writeRevisionFile() +{ + SGPath revisionFile = m_path; + revisionFile.append(".revision"); + std::ofstream f(revisionFile.c_str(), std::ios::out | std::ios::trunc); + f << m_revision << std::endl; +} + +bool Install::hasUpdate() const +{ + return m_package->revision() > m_revision; +} + +void Install::startUpdate() +{ + if (m_download) { + return; // already active + } + + m_download = new PackageArchiveDownloader(this); + m_package->catalog()->root()->makeHTTPRequest(m_download); + m_package->catalog()->root()->startInstall(this); +} + +void Install::uninstall() +{ + Dir d(m_path); + d.remove(true); + delete this; +} + +void Install::installResult(Delegate::FailureCode aReason) +{ + if (aReason == Delegate::FAIL_SUCCESS) { + m_package->catalog()->root()->finishInstall(this); + } else { + m_package->catalog()->root()->failedInstall(this, aReason); + } +} + +void Install::installProgress(unsigned int aBytes, unsigned int aTotal) +{ + m_package->catalog()->root()->installProgress(this, aBytes, aTotal); +} + + +} // of namespace pkg + +} // of namespace simgear diff -Nru simgear-2.10.0/simgear/package/Install.hxx simgear-3.0.0/simgear/package/Install.hxx --- simgear-2.10.0/simgear/package/Install.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/Install.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,93 @@ +// Copyright (C) 2013 James Turner - zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef SG_PACKAGE_INSTALL_HXX +#define SG_PACKAGE_INSTALL_HXX + +#include + +#include +#include + +namespace simgear +{ + +namespace pkg +{ + +// forward decls +class Package; +class Catalog; + +/** + * + */ +class Install +{ +public: + /** + * create from a directory on disk, or fail. + */ + static Install* createFromPath(const SGPath& aPath, Catalog* aCat); + + unsigned int revsion() const + { return m_revision; } + + Package* package() const + { return m_package; } + + SGPath path() const + { return m_path; } + + bool hasUpdate() const; + + void startUpdate(); + + void uninstall(); + +// boost signals time? + // failure + // progress + // completed + +private: + friend class Package; + + class PackageArchiveDownloader; + friend class PackageArchiveDownloader; + + Install(Package* aPkg, const SGPath& aPath); + + void parseRevision(); + void writeRevisionFile(); + + void installResult(Delegate::FailureCode aReason); + void installProgress(unsigned int aBytes, unsigned int aTotal); + + Package* m_package; + unsigned int m_revision; ///< revision on disk + SGPath m_path; ///< installation point on disk + + PackageArchiveDownloader* m_download; +}; + + +} // of namespace pkg + +} // of namespace simgear + +#endif // of SG_PACKAGE_CATALOG_HXX diff -Nru simgear-2.10.0/simgear/package/ioapi.c simgear-3.0.0/simgear/package/ioapi.c --- simgear-2.10.0/simgear/package/ioapi.c 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/ioapi.c 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,178 @@ +/* ioapi.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant +*/ + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + + + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +voidpf ZCALLBACK fopen_file_func OF(( + voidpf opaque, + const char* filename, + int mode)); + +uLong ZCALLBACK fread_file_func OF(( + voidpf opaque, + voidpf stream, + void* buf, + uLong size)); + +uLong ZCALLBACK fwrite_file_func OF(( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size)); + +long ZCALLBACK ftell_file_func OF(( + voidpf opaque, + voidpf stream)); + +long ZCALLBACK fseek_file_func OF(( + voidpf opaque, + voidpf stream, + uLong offset, + int origin)); + +int ZCALLBACK fclose_file_func OF(( + voidpf opaque, + voidpf stream)); + +int ZCALLBACK ferror_file_func OF(( + voidpf opaque, + voidpf stream)); + + +voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + + +uLong ZCALLBACK fread_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + + +uLong ZCALLBACK fwrite_file_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +long ZCALLBACK ftell_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + +long ZCALLBACK fseek_file_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +int ZCALLBACK fclose_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +int ZCALLBACK ferror_file_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff -Nru simgear-2.10.0/simgear/package/ioapi.h simgear-3.0.0/simgear/package/ioapi.h --- simgear-2.10.0/simgear/package/ioapi.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/ioapi.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,80 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant +*/ + +#ifndef _ZLIBIOAPI_H +#define _ZLIBIOAPI_H + +// Needed for some zlib installations: +#ifndef OF + #define OF(x) x +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + +#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) +#define ZCALLBACK CALLBACK +#else +#define ZCALLBACK +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + + + +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) +#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) +#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream)) +#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream)) +#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream)) + + +#ifdef __cplusplus +} +#endif + +#endif + diff -Nru simgear-2.10.0/simgear/package/ioapi_mem.c simgear-3.0.0/simgear/package/ioapi_mem.c --- simgear-2.10.0/simgear/package/ioapi_mem.c 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/ioapi_mem.c 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,221 @@ +/* ioapi_mem.c -- IO base function header for compress/uncompress .zip + files using zlib + zip or unzip API + + This version of ioapi is designed to access memory rather than files. + We do use a region of memory to put data in to and take it out of. We do + not have auto-extending buffers and do not inform anyone else that the + data has been written. It is really intended for accessing a zip archive + embedded in an application such that I can write an installer with no + external files. Creation of archives has not been attempted, although + parts of the framework are present. + + Based on Unzip ioapi.c version 0.22, May 19th, 2003 + + Copyright (C) 1998-2003 Gilles Vollant + (C) 2003 Justin Fletcher + + This file is under the same license as the Unzip tool it is distributed + with. +*/ + + +#include +#include +#include + +#include "zlib.h" +#include "ioapi.h" + + + +voidpf ZCALLBACK fopen_mem_func OF(( + voidpf opaque, + const char* filename, + int mode)); + +uLong ZCALLBACK fread_mem_func OF(( + voidpf opaque, + voidpf stream, + void* buf, + uLong size)); + +uLong ZCALLBACK fwrite_mem_func OF(( + voidpf opaque, + voidpf stream, + const void* buf, + uLong size)); + +long ZCALLBACK ftell_mem_func OF(( + voidpf opaque, + voidpf stream)); + +long ZCALLBACK fseek_mem_func OF(( + voidpf opaque, + voidpf stream, + uLong offset, + int origin)); + +int ZCALLBACK fclose_mem_func OF(( + voidpf opaque, + voidpf stream)); + +int ZCALLBACK ferror_mem_func OF(( + voidpf opaque, + voidpf stream)); + + +typedef struct ourmemory_s { + char *base; /* Base of the region of memory we're using */ + uLong size; /* Size of the region of memory we're using */ + uLong limit; /* Furthest we've written */ + uLong cur_offset; /* Current offset in the area */ +} ourmemory_t; + +voidpf ZCALLBACK fopen_mem_func (opaque, filename, mode) + voidpf opaque; + const char* filename; + int mode; +{ + ourmemory_t *mem = malloc(sizeof(*mem)); + if (mem==NULL) + return NULL; /* Can't allocate space, so failed */ + + memset(mem, 0, sizeof(ourmemory_t)); + + /* Filenames are specified in the form : + * + + * This may not work where memory addresses are longer than the + * size of an int and therefore may need addressing for 64bit + * architectures + */ + if (sscanf(filename,"%p+%x",&mem->base,&mem->size)!=2) + return NULL; + + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mem->limit=0; /* When writing we start with 0 bytes written */ + else + mem->limit=mem->size; + + mem->cur_offset = 0; + + return mem; +} + + +uLong ZCALLBACK fread_mem_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + void* buf; + uLong size; +{ + ourmemory_t *mem = (ourmemory_t *)stream; + + if (size > mem->size - mem->cur_offset) + size = mem->size - mem->cur_offset; + + memcpy(buf, mem->base + mem->cur_offset, size); + mem->cur_offset+=size; + + return size; +} + + +uLong ZCALLBACK fwrite_mem_func (opaque, stream, buf, size) + voidpf opaque; + voidpf stream; + const void* buf; + uLong size; +{ + ourmemory_t *mem = (ourmemory_t *)stream; + + if (size > mem->size - mem->cur_offset) + size = mem->size - mem->cur_offset; + + memcpy(mem->base + mem->cur_offset, buf, size); + mem->cur_offset+=size; + if (mem->cur_offset > mem->limit) + mem->limit = mem->cur_offset; + + return size; +} + +long ZCALLBACK ftell_mem_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + ourmemory_t *mem = (ourmemory_t *)stream; + + return mem->cur_offset; +} + +long ZCALLBACK fseek_mem_func (opaque, stream, offset, origin) + voidpf opaque; + voidpf stream; + uLong offset; + int origin; +{ + ourmemory_t *mem = (ourmemory_t *)stream; + uLong new_pos; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + new_pos = mem->cur_offset + offset; + break; + case ZLIB_FILEFUNC_SEEK_END : + new_pos = mem->limit + offset; + break; + case ZLIB_FILEFUNC_SEEK_SET : + new_pos = offset; + break; + default: return -1; + } + + if (new_pos > mem->size) + return 1; /* Failed to seek that far */ + + if (new_pos > mem->limit) + memset(mem->base + mem->limit, 0, new_pos - mem->limit); + + mem->cur_offset = new_pos; + return 0; +} + +int ZCALLBACK fclose_mem_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + ourmemory_t *mem = (ourmemory_t *)stream; + + /* Note that once we've written to the buffer we don't tell anyone + about it here. Probably the opaque handle could be used to inform + some other component of how much data was written. + + This, and other aspects of writing through this interface, has + not been tested. + */ + + free (mem); + return 0; +} + +int ZCALLBACK ferror_mem_func (opaque, stream) + voidpf opaque; + voidpf stream; +{ + ourmemory_t *mem = (ourmemory_t *)stream; + /* We never return errors */ + return 0; +} + +void fill_memory_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_mem_func; + pzlib_filefunc_def->zread_file = fread_mem_func; + pzlib_filefunc_def->zwrite_file = fwrite_mem_func; + pzlib_filefunc_def->ztell_file = ftell_mem_func; + pzlib_filefunc_def->zseek_file = fseek_mem_func; + pzlib_filefunc_def->zclose_file = fclose_mem_func; + pzlib_filefunc_def->zerror_file = ferror_mem_func; + pzlib_filefunc_def->opaque = NULL; +} diff -Nru simgear-2.10.0/simgear/package/md5.c simgear-3.0.0/simgear/package/md5.c --- simgear-2.10.0/simgear/package/md5.c 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/md5.c 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,250 @@ +/* $OpenBSD: md5.c,v 1.7 2004/05/28 15:10:27 millert Exp $ */ + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + + +#include +#include + +#include "md5.h" + +#define PUT_64BIT_LE(cp, value) do { \ + (cp)[7] = (value) >> 56; \ + (cp)[6] = (value) >> 48; \ + (cp)[5] = (value) >> 40; \ + (cp)[4] = (value) >> 32; \ + (cp)[3] = (value) >> 24; \ + (cp)[2] = (value) >> 16; \ + (cp)[1] = (value) >> 8; \ + (cp)[0] = (value); } while (0) + +#define PUT_32BIT_LE(cp, value) do { \ + (cp)[3] = (value) >> 24; \ + (cp)[2] = (value) >> 16; \ + (cp)[1] = (value) >> 8; \ + (cp)[0] = (value); } while (0) + +static u_int8_t PADDING[MD5_BLOCK_LENGTH] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +SG_MD5Init(SG_MD5_CTX *ctx) +{ + ctx->count = 0; + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xefcdab89; + ctx->state[2] = 0x98badcfe; + ctx->state[3] = 0x10325476; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +SG_MD5Update(SG_MD5_CTX *ctx, const unsigned char *input, size_t len) +{ + size_t have, need; + + /* Check how many bytes we already have and how many more we need. */ + have = (size_t)((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1)); + need = MD5_BLOCK_LENGTH - have; + + /* Update bitcount */ + ctx->count += (u_int64_t)len << 3; + + if (len >= need) { + if (have != 0) { + memcpy(ctx->buffer + have, input, need); + SG_MD5Transform(ctx->state, ctx->buffer); + input += need; + len -= need; + have = 0; + } + + /* Process data in MD5_BLOCK_LENGTH-byte chunks. */ + while (len >= MD5_BLOCK_LENGTH) { + SG_MD5Transform(ctx->state, input); + input += MD5_BLOCK_LENGTH; + len -= MD5_BLOCK_LENGTH; + } + } + + /* Handle any remaining bytes of data. */ + if (len != 0) + memcpy(ctx->buffer + have, input, len); +} + +/* + * Pad pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +SG_MD5Pad(SG_MD5_CTX *ctx) +{ + u_int8_t count[8]; + size_t padlen; + + /* Convert count to 8 bytes in little endian order. */ + PUT_64BIT_LE(count, ctx->count); + + /* Pad out to 56 mod 64. */ + padlen = MD5_BLOCK_LENGTH - + ((ctx->count >> 3) & (MD5_BLOCK_LENGTH - 1)); + if (padlen < 1 + 8) + padlen += MD5_BLOCK_LENGTH; + SG_MD5Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */ + SG_MD5Update(ctx, count, 8); +} + +/* + * Final wrapup--call MD5Pad, fill in digest and zero out ctx. + */ +void +SG_MD5Final(unsigned char digest[MD5_DIGEST_LENGTH], SG_MD5_CTX *ctx) +{ + int i; + + SG_MD5Pad(ctx); + if (digest != NULL) { + for (i = 0; i < 4; i++) + PUT_32BIT_LE(digest + i * 4, ctx->state[i]); + memset(ctx, 0, sizeof(*ctx)); + } +} + + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +SG_MD5Transform(u_int32_t state[4], const u_int8_t block[MD5_BLOCK_LENGTH]) +{ + u_int32_t a, b, c, d, in[MD5_BLOCK_LENGTH / 4]; + +#ifndef WORDS_BIGENDIAN + memcpy(in, block, sizeof(in)); +#else + for (a = 0; a < MD5_BLOCK_LENGTH / 4; a++) { + in[a] = (u_int32_t)( + (u_int32_t)(block[a * 4 + 0]) | + (u_int32_t)(block[a * 4 + 1]) << 8 | + (u_int32_t)(block[a * 4 + 2]) << 16 | + (u_int32_t)(block[a * 4 + 3]) << 24); + } +#endif + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + + MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2 ] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7 ] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5 ] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3 ] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1 ] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8 ] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6 ] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4 ] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2 ] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9 ] + 0xeb86d391, 21); + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; +} \ No newline at end of file diff -Nru simgear-2.10.0/simgear/package/md5.h simgear-3.0.0/simgear/package/md5.h --- simgear-2.10.0/simgear/package/md5.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/md5.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,52 @@ + /* $OpenBSD: md5.h,v 1.15 2004/05/03 17:30:14 millert Exp $ */ + +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + */ + +#ifndef _MD5_H_ +#define _MD5_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#if defined(_MSC_VER) +typedef unsigned char u_int8_t; +typedef unsigned int u_int32_t; +typedef unsigned __int64 u_int64_t; +#endif + +#define MD5_BLOCK_LENGTH 64 +#define MD5_DIGEST_LENGTH 16 +#define MD5_DIGEST_STRING_LENGTH (MD5_DIGEST_LENGTH * 2 + 1) + +typedef struct MD5Context { + u_int32_t state[4]; /* state */ + u_int64_t count; /* number of bits, mod 2^64 */ + u_int8_t buffer[MD5_BLOCK_LENGTH]; /* input buffer */ +} SG_MD5_CTX; + +void SG_MD5Init(SG_MD5_CTX *); +void SG_MD5Update(SG_MD5_CTX *, const u_int8_t *, size_t); +void SG_MD5Pad(SG_MD5_CTX *); +void SG_MD5Final(u_int8_t [MD5_DIGEST_LENGTH], SG_MD5_CTX *); +void SG_MD5Transform(u_int32_t [4], const u_int8_t [MD5_BLOCK_LENGTH]); + +#ifdef __cplusplus +} // of extern C +#endif + +#endif /* _MD5_H_ */ + + + + \ No newline at end of file diff -Nru simgear-2.10.0/simgear/package/Package.cxx simgear-3.0.0/simgear/package/Package.cxx --- simgear-2.10.0/simgear/package/Package.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/Package.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,202 @@ +// Copyright (C) 2013 James Turner - zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include + +#include +#include + +#include +#include + +#include +#include +#include + +namespace simgear { + +namespace pkg { + +Package::Package(const SGPropertyNode* aProps, Catalog* aCatalog) : + m_catalog(aCatalog) +{ + initWithProps(aProps); +} + +void Package::initWithProps(const SGPropertyNode* aProps) +{ + m_props = const_cast(aProps); +// cache tag values + BOOST_FOREACH(const SGPropertyNode* c, aProps->getChildren("tag")) { + m_tags.insert(c->getStringValue()); + } +} + +bool Package::matches(const SGPropertyNode* aFilter) const +{ + int nChildren = aFilter->nChildren(); + for (int i = 0; i < nChildren; i++) { + const SGPropertyNode* c = aFilter->getChild(i); + if (strutils::starts_with(c->getName(), "rating-")) { + int minRating = c->getIntValue(); + std::string rname = c->getName() + 7; + int ourRating = m_props->getChild("rating")->getIntValue(rname, 0); + if (ourRating < minRating) { + return false; + } + } + + if (strcmp(c->getName(), "tag") == 0) { + std::string tag(c->getStringValue()); + if (m_tags.find(tag) == m_tags.end()) { + return false; + } + } + + SG_LOG(SG_GENERAL, SG_WARN, "unknown filter term:" << c->getName()); + } // of filter props iteration + + return true; +} + +bool Package::isInstalled() const +{ + SGPath p(m_catalog->installRoot()); + p.append("Aircraft"); + p.append(id()); + + // anything to check for? look for a valid revision file? + return p.exists(); +} + +Install* Package::install() +{ + SGPath p(m_catalog->installRoot()); + p.append("Aircraft"); + p.append(id()); + if (p.exists()) { + return Install::createFromPath(p, m_catalog); + } + + Install* ins = new Install(this, p); + m_catalog->root()->scheduleToUpdate(ins); + return ins; +} + +std::string Package::id() const +{ + return m_props->getStringValue("id"); +} + +std::string Package::md5() const +{ + return m_props->getStringValue("md5"); +} + +unsigned int Package::revision() const +{ + return m_props->getIntValue("revision"); +} + +std::string Package::name() const +{ + return m_props->getStringValue("name"); +} + +std::string Package::description() const +{ + return getLocalisedProp("decription"); +} + +SGPropertyNode* Package::properties() const +{ + return m_props.ptr(); +} + +string_list Package::thumbnailUrls() const +{ + string_list r; + BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("thumbnail")) { + r.push_back(dl->getStringValue()); + } + return r; +} + +string_list Package::downloadUrls() const +{ + string_list r; + BOOST_FOREACH(SGPropertyNode* dl, m_props->getChildren("download")) { + r.push_back(dl->getStringValue()); + } + return r; +} + +std::string Package::getLocalisedProp(const std::string& aName) const +{ + return getLocalisedString(m_props, aName.c_str()); +} + +std::string Package::getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const +{ + std::string locale = m_catalog->root()->getLocale(); + if (aRoot->hasChild(locale)) { + const SGPropertyNode* localeRoot = aRoot->getChild(locale.c_str()); + if (localeRoot->hasChild(aName)) { + return localeRoot->getStringValue(aName); + } + } + + return aRoot->getStringValue(aName); +} + +PackageList Package::dependencies() const +{ + PackageList result; + + BOOST_FOREACH(SGPropertyNode* dep, m_props->getChildren("depends")) { + std::string depName = dep->getStringValue("package"); + unsigned int rev = dep->getIntValue("revision", 0); + + // prefer local hangar package if possible, in case someone does something + // silly with naming. Of course flightgear's aircraft search doesn't know + // about hanagrs, so names still need to be unique. + Package* depPkg = m_catalog->getPackageById(depName); + if (!depPkg) { + Root* rt = m_catalog->root(); + depPkg = rt->getPackageById(depName); + if (!depPkg) { + throw sg_exception("Couldn't satisfy dependency of " + id() + " : " + depName); + } + } + + if (depPkg->revision() < rev) { + throw sg_range_exception("Couldn't find suitable revision of " + depName); + } + + // forbid recursive dependency graphs, we don't need that level + // of complexity for aircraft resources + assert(depPkg->dependencies() == PackageList()); + + result.push_back(depPkg); + } + + return result; +} + +} // of namespace pkg + +} // of namespace simgear diff -Nru simgear-2.10.0/simgear/package/Package.hxx simgear-3.0.0/simgear/package/Package.hxx --- simgear-2.10.0/simgear/package/Package.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/Package.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,119 @@ +// Copyright (C) 2013 James Turner - zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef SG_PACKAGE_PACKAGE_HXX +#define SG_PACKAGE_PACKAGE_HXX + +#include +#include + +#include +#include + +typedef std::set string_set; + +namespace simgear +{ + +namespace pkg +{ + +// forward decls +class Install; +class Catalog; +class Package; + +typedef std::vector PackageList; + +class Package +{ +public: + /** + * get or create an install for the package + */ + Install* install(); + + bool isInstalled() const; + + std::string id() const; + + /** + * human-readable name - note this is probably not localised, + * although this is not ruled out for the future. + */ + std::string name() const; + + /** + * syntactic sugar to get the localised description + */ + std::string description() const; + + /** + * access the raw property data in the package + */ + SGPropertyNode* properties() const; + + /** + * hex-encoded MD5 sum of the download files + */ + std::string md5() const; + + std::string getLocalisedProp(const std::string& aName) const; + + unsigned int revision() const; + + Catalog* catalog() const + { return m_catalog; } + + bool matches(const SGPropertyNode* aFilter) const; + + /** + * download URLs for the package + */ + string_list downloadUrls() const; + + string_list thumbnailUrls() const; + + /** + * Packages we depend upon. + * If the dependency list cannot be satisifed for some reason, + * this will raise an sg_exception. + */ + PackageList dependencies() const; +private: + friend class Catalog; + + Package(const SGPropertyNode* aProps, Catalog* aCatalog); + + void initWithProps(const SGPropertyNode* aProps); + + std::string getLocalisedString(const SGPropertyNode* aRoot, const char* aName) const; + + SGPropertyNode_ptr m_props; + string_set m_tags; + Catalog* m_catalog; +}; + + + + +} // of namespace pkg + +} // of namespace simgear + +#endif // of SG_PACKAGE_PACKAGE_HXX + diff -Nru simgear-2.10.0/simgear/package/pkgutil.cxx simgear-3.0.0/simgear/package/pkgutil.cxx --- simgear-2.10.0/simgear/package/pkgutil.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/pkgutil.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,198 @@ +// Copyright (C) 2013 James Turner - zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace simgear; +using namespace std; + +bool keepRunning = true; + +class MyDelegate : public pkg::Delegate +{ +public: + virtual void refreshComplete() + { + } + + virtual void failedRefresh(pkg::Catalog* aCatalog, FailureCode aReason) + { + cerr << "failed refresh of " << aCatalog->description() << ":" << aReason << endl; + } + + virtual void startInstall(pkg::Install* aInstall) + { + _lastPercent = 999; + cout << "starting install of " << aInstall->package()->name() << endl; + } + + virtual void installProgress(pkg::Install* aInstall, unsigned int bytes, unsigned int total) + { + unsigned int percent = (bytes * 100) / total; + if (percent == _lastPercent) { + return; + } + + _lastPercent = percent; + cout << percent << "%" << endl; + } + + virtual void finishInstall(pkg::Install* aInstall) + { + cout << "done install of " << aInstall->package()->name() << endl; + } + + virtual void failedInstall(pkg::Install* aInstall, FailureCode aReason) + { + cerr << "failed install of " << aInstall->package()->name() << endl; + } +private: + unsigned int _lastPercent; + +}; + +void printRating(pkg::Package* pkg, const std::string& aRating, const std::string& aLabel) +{ + SGPropertyNode* ratings = pkg->properties()->getChild("rating"); + cout << "\t" << aLabel << ":" << ratings->getIntValue(aRating) << endl; +} + +void printPackageInfo(pkg::Package* pkg) +{ + cout << "Package:" << pkg->catalog()->id() << "." << pkg->id() << endl; + cout << "Revision:" << pkg->revision() << endl; + cout << "Name:" << pkg->name() << endl; + cout << "Description:" << pkg->description() << endl; + cout << "Long description:\n" << pkg->getLocalisedProp("long-description") << endl << endl; + + if (pkg->properties()->hasChild("author")) { + cout << "Authors:" << endl; + BOOST_FOREACH(SGPropertyNode* author, pkg->properties()->getChildren("author")) { + if (author->hasChild("name")) { + cout << "\t" << author->getStringValue("name") << endl; + + } else { + // simple author structure + cout << "\t" << author->getStringValue() << endl; + } + + + } + + cout << endl; + } + + cout << "Ratings:" << endl; + printRating(pkg, "fdm", "Flight-model "); + printRating(pkg, "cockpit", "Cockpit "); + printRating(pkg, "model", "3D model "); + printRating(pkg, "systems", "Aircraft systems"); +} + +int main(int argc, char** argv) +{ + + HTTP::Client* http = new HTTP::Client(); + pkg::Root* root = new pkg::Root(Dir::current().path(), ""); + + MyDelegate dlg; + root->setDelegate(&dlg); + + cout << "Package root is:" << Dir::current().path() << endl; + cout << "have " << pkg::Catalog::allCatalogs().size() << " catalog(s)" << endl; + + root->setHTTPClient(http); + + if (!strcmp(argv[1], "add")) { + std::string url(argv[2]); + pkg::Catalog::createFromUrl(root, url); + } else if (!strcmp(argv[1], "refresh")) { + root->refresh(true); + } else if (!strcmp(argv[1], "install")) { + pkg::Package* pkg = root->getPackageById(argv[2]); + if (!pkg) { + cerr << "unknown package:" << argv[2] << endl; + return EXIT_FAILURE; + } + + if (pkg->isInstalled()) { + cout << "package " << pkg->id() << " is already installed at " << pkg->install()->path() << endl; + return EXIT_SUCCESS; + } + + pkg::Catalog* catalog = pkg->catalog(); + cout << "Will install:" << pkg->id() << " from " << catalog->id() << + "(" << catalog->description() << ")" << endl; + pkg->install(); + } else if (!strcmp(argv[1], "uninstall") || !strcmp(argv[1], "remove")) { + pkg::Package* pkg = root->getPackageById(argv[2]); + if (!pkg) { + cerr << "unknown package:" << argv[2] << endl; + return EXIT_FAILURE; + } + + if (!pkg->isInstalled()) { + cerr << "package " << argv[2] << " not installed" << endl; + return EXIT_FAILURE; + } + + cout << "Will uninstall:" << pkg->id() << endl; + pkg->install()->uninstall(); + } else if (!strcmp(argv[1], "update-all")) { + pkg::PackageList updates = root->packagesNeedingUpdate(); + BOOST_FOREACH(pkg::Package* p, updates) { + root->scheduleToUpdate(p->install()); + } + } else if (!strcmp(argv[1], "list-updated")) { + pkg::PackageList updates = root->packagesNeedingUpdate(); + if (updates.empty()) { + cout << "no packages with updates" << endl; + return EXIT_SUCCESS; + } + + cout << updates.size() << " packages have updates" << endl; + BOOST_FOREACH(pkg::Package* p, updates) { + cout << "\t" << p->id() << " " << p->getLocalisedProp("name") << endl; + } + } else if (!strcmp(argv[1], "info")) { + pkg::Package* pkg = root->getPackageById(argv[2]); + if (!pkg) { + cerr << "unknown package:" << argv[2] << endl; + return EXIT_FAILURE; + } + + printPackageInfo(pkg); + } else { + cerr << "unknown command:" << argv[1] << endl; + return EXIT_FAILURE; + } + + while (http->hasActiveRequests()) { + http->update(); + } + + return EXIT_SUCCESS; +} diff -Nru simgear-2.10.0/simgear/package/Root.cxx simgear-3.0.0/simgear/package/Root.cxx --- simgear-2.10.0/simgear/package/Root.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/Root.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,339 @@ +// Copyright (C) 2013 James Turner - zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace simgear { + +namespace pkg { + +typedef std::map CatalogDict; + +class Root::RootPrivate +{ +public: + RootPrivate() : + http(NULL), + maxAgeSeconds(60 * 60 * 24), + delegate(NULL) + { + + } + + SGPath path; + std::string locale; + HTTP::Client* http; + CatalogDict catalogs; + unsigned int maxAgeSeconds; + Delegate* delegate; + std::string version; + + std::set refreshing; + std::deque updateDeque; + std::deque httpPendingRequests; +}; + +SGPath Root::path() const +{ + return d->path; +} + +void Root::setMaxAgeSeconds(unsigned int seconds) +{ + d->maxAgeSeconds = seconds; +} + +unsigned int Root::maxAgeSeconds() const +{ + return d->maxAgeSeconds; +} + +void Root::setHTTPClient(HTTP::Client* aHTTP) +{ + d->http = aHTTP; + BOOST_FOREACH(HTTP::Request_ptr req, d->httpPendingRequests) { + d->http->makeRequest(req); + } + + d->httpPendingRequests.clear(); +} + +void Root::makeHTTPRequest(HTTP::Request *req) +{ + if (d->http) { + d->http->makeRequest(req); + return; + } + + d->httpPendingRequests.push_back(req); +} + +Root::Root(const SGPath& aPath, const std::string& aVersion) : + d(new RootPrivate) +{ + d->path = aPath; + d->version = aVersion; + if (getenv("LOCALE")) { + d->locale = getenv("LOCALE"); + } + + Dir dir(aPath); + if (!dir.exists()) { + dir.create(0755); + return; + } + + BOOST_FOREACH(SGPath c, dir.children(Dir::TYPE_DIR)) { + Catalog* cat = Catalog::createFromPath(this, c); + if (cat) { + d->catalogs[cat->id()] = cat; + } + } // of child directories iteration +} + +Root::~Root() +{ + +} + +std::string Root::catalogVersion() const +{ + return d->version; +} + +Catalog* Root::getCatalogById(const std::string& aId) const +{ + CatalogDict::const_iterator it = d->catalogs.find(aId); + if (it == d->catalogs.end()) { + return NULL; + } + + return it->second; +} + +Package* Root::getPackageById(const std::string& aName) const +{ + size_t lastDot = aName.rfind('.'); + + Package* pkg = NULL; + if (lastDot == std::string::npos) { + // naked package ID + CatalogDict::const_iterator it = d->catalogs.begin(); + for (; it != d->catalogs.end(); ++it) { + pkg = it->second->getPackageById(aName); + if (pkg) { + return pkg; + } + } + + return NULL; + } + + std::string catalogId = aName.substr(0, lastDot); + std::string id = aName.substr(lastDot + 1); + Catalog* catalog = getCatalogById(catalogId); + if (!catalog) { + return NULL; + } + + return catalog->getPackageById(id); +} + +CatalogList Root::catalogs() const +{ + CatalogList r; + CatalogDict::const_iterator it = d->catalogs.begin(); + for (; it != d->catalogs.end(); ++it) { + r.push_back(it->second); + } + + return r; +} + +PackageList +Root::packagesMatching(const SGPropertyNode* aFilter) const +{ + PackageList r; + + CatalogDict::const_iterator it = d->catalogs.begin(); + for (; it != d->catalogs.end(); ++it) { + PackageList r2(it->second->packagesMatching(aFilter)); + r.insert(r.end(), r2.begin(), r2.end()); + } + + return r; +} + +PackageList +Root::packagesNeedingUpdate() const +{ + PackageList r; + + CatalogDict::const_iterator it = d->catalogs.begin(); + for (; it != d->catalogs.end(); ++it) { + PackageList r2(it->second->packagesNeedingUpdate()); + r.insert(r.end(), r2.begin(), r2.end()); + } + + return r; +} + +void Root::refresh(bool aForce) +{ + CatalogDict::iterator it = d->catalogs.begin(); + for (; it != d->catalogs.end(); ++it) { + if (aForce || it->second->needsRefresh()) { + it->second->refresh(); + } + } +} + +void Root::setDelegate(simgear::pkg::Delegate *aDelegate) +{ + d->delegate = aDelegate; +} + +void Root::setLocale(const std::string& aLocale) +{ + d->locale = aLocale; +} + +std::string Root::getLocale() const +{ + return d->locale; +} + +void Root::scheduleToUpdate(Install* aInstall) +{ + if (!aInstall) { + sg_exception("missing argument to scheduleToUpdate"); + } + + PackageList deps = aInstall->package()->dependencies(); + BOOST_FOREACH(Package* dep, deps) { + // will internally schedule for update if required + // hence be careful, this method is re-entered in here! + dep->install(); + } + + bool wasEmpty = d->updateDeque.empty(); + d->updateDeque.push_back(aInstall); + + if (wasEmpty) { + aInstall->startUpdate(); + } +} + +void Root::startInstall(Install* aInstall) +{ + if (d->delegate) { + d->delegate->startInstall(aInstall); + } +} + +void Root::installProgress(Install* aInstall, unsigned int aBytes, unsigned int aTotal) +{ + if (d->delegate) { + d->delegate->installProgress(aInstall, aBytes, aTotal); + } +} + +void Root::startNext(Install* aCurrent) +{ + if (d->updateDeque.front() != aCurrent) { + SG_LOG(SG_GENERAL, SG_ALERT, "current install of package not head of the deque"); + } else { + d->updateDeque.pop_front(); + } + + if (!d->updateDeque.empty()) { + d->updateDeque.front()->startUpdate(); + } +} + +void Root::finishInstall(Install* aInstall) +{ + if (d->delegate) { + d->delegate->finishInstall(aInstall); + } + + startNext(aInstall); +} + +void Root::failedInstall(Install* aInstall, Delegate::FailureCode aReason) +{ + SG_LOG(SG_GENERAL, SG_ALERT, "failed to install package:" + << aInstall->package()->id() << ":" << aReason); + if (d->delegate) { + d->delegate->failedInstall(aInstall, aReason); + } + + startNext(aInstall); +} + +void Root::catalogRefreshBegin(Catalog* aCat) +{ + d->refreshing.insert(aCat); +} + +void Root::catalogRefreshComplete(Catalog* aCat, Delegate::FailureCode aReason) +{ + CatalogDict::iterator catIt = d->catalogs.find(aCat->id()); + if (aReason != Delegate::FAIL_SUCCESS) { + if (d->delegate) { + d->delegate->failedRefresh(aCat, aReason); + } + + // if the failure is permanent, delete the catalog from our + // list (don't touch it on disk) + bool isPermanentFailure = (aReason == Delegate::FAIL_VERSION); + if (isPermanentFailure) { + SG_LOG(SG_GENERAL, SG_WARN, "permanent failure for catalog:" << aCat->id()); + d->catalogs.erase(catIt); + } + } else if (catIt == d->catalogs.end()) { + // first fresh, add to our storage now + d->catalogs.insert(catIt, CatalogDict::value_type(aCat->id(), aCat)); + } + + d->refreshing.erase(aCat); + if (d->refreshing.empty()) { + if (d->delegate) { + d->delegate->refreshComplete(); + } + } +} + +} // of namespace pkg + +} // of namespace simgear diff -Nru simgear-2.10.0/simgear/package/Root.hxx simgear-3.0.0/simgear/package/Root.hxx --- simgear-2.10.0/simgear/package/Root.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/Root.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,128 @@ +// Copyright (C) 2013 James Turner - zakalawe@mac.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef SG_PACKAGE_ROOT_HXX +#define SG_PACKAGE_ROOT_HXX + +#include +#include // for auto_ptr + +#include +#include + +class SGPropertyNode; + +namespace simgear +{ + +namespace HTTP { + class Client; + class Request; +} + +namespace pkg +{ + +// forward decls +class Package; +class Catalog; +class Install; + +typedef std::vector PackageList; +typedef std::vector CatalogList; + +class Root +{ +public: + Root(const SGPath& aPath, const std::string& aVersion); + virtual ~Root(); + + SGPath path() const; + + void setLocale(const std::string& aLocale); + + void setDelegate(Delegate* aDelegate); + + std::string getLocale() const; + + CatalogList catalogs() const; + + void setMaxAgeSeconds(unsigned int seconds); + unsigned int maxAgeSeconds() const; + + void setHTTPClient(HTTP::Client* aHTTP); + + /** + * Submit an HTTP request. The Root may delay or queue requests if it needs + * too, for example during startup when the HTTP engine may not have been + * set yet. + */ + void makeHTTPRequest(HTTP::Request* req); + + /** + * the version string of the root. Catalogs must match this version, + * or they will be ignored / rejected. + */ + std::string catalogVersion() const; + + /** + * refresh catalogs which are more than the maximum age (24 hours by default) + * set force to true, to download all catalogs regardless of age. + */ + void refresh(bool aForce = false); + + /** + * retrieve packages matching a filter. + * filter consists of required / minimum values, AND-ed together. + */ + PackageList packagesMatching(const SGPropertyNode* aFilter) const; + + /** + * retrieve all the packages which are installed + * and have a pending update + */ + PackageList packagesNeedingUpdate() const; + + Package* getPackageById(const std::string& aId) const; + + Catalog* getCatalogById(const std::string& aId) const; + + void scheduleToUpdate(Install* aInstall); +private: + friend class Install; + friend class Catalog; + + + void catalogRefreshBegin(Catalog* aCat); + void catalogRefreshComplete(Catalog* aCat, Delegate::FailureCode aReason); + + void startNext(Install* aCurrent); + + void startInstall(Install* aInstall); + void installProgress(Install* aInstall, unsigned int aBytes, unsigned int aTotal); + void finishInstall(Install* aInstall); + void failedInstall(Install* aInstall, Delegate::FailureCode aReason); + + class RootPrivate; + std::auto_ptr d; +}; + +} // of namespace pkg + +} // of namespace simgear + +#endif // of SG_PACKAGE_ROOT_HXX diff -Nru simgear-2.10.0/simgear/package/unzip.c simgear-3.0.0/simgear/package/unzip.c --- simgear-2.10.0/simgear/package/unzip.c 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/unzip.c 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,1701 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant + + Read unzip.h for more info +*/ + +/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of +compatibility with older software. The following is from the original crypt.c. Code +woven in by Terry Thorsen 1/2003. +*/ +/* + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html +*/ +/* + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + */ + +/* + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + */ + +#define NOUNCRYPT + +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + uLong offset_curfile;/* relative offset of local header 4 bytes */ +} unz_file_info_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + uLong pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + uLong offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + uLong pos_local_extrafield; /* position in the local extra field in read*/ + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + uLong rest_read_compressed; /* number of byte to be decompressed */ + uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + uLong num_file; /* number of the current file in the zipfile*/ + uLong pos_in_central_dir; /* pos of the current file in the central dir*/ + uLong current_file_ok; /* flag about the usability of the current file*/ + uLong central_pos; /* position of the beginning of the central dir*/ + + uLong size_central_dir; /* size of the central directory */ + uLong offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unzlocal_getByte OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + int *pi; +{ + unsigned char c; + int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unzlocal_getShort OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i = 0; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unzlocal_getLong OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; + uLong *pX; +{ + uLong x ; + int i = 0; + int err; + + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (fileName1,fileName2) + const char* fileName1; + const char* fileName2; +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity) + const char* fileName1; + const char* fileName2; + int iCaseSensitivity; +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local uLong unzlocal_SearchCentralDir OF(( + const zlib_filefunc_def* pzlib_filefunc_def, + voidpf filestream)); + +local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) + const zlib_filefunc_def* pzlib_filefunc_def; + voidpf filestream; +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile ZEXPORT unzOpen2 (path, pzlib_filefunc_def) + const char *path; + zlib_filefunc_def* pzlib_filefunc_def; +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + if (pzlib_filefunc_def==NULL) + fill_fopen_filefunc(&us.z_filefunc); + else + us.z_filefunc = *pzlib_filefunc_def; + + us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + if (ZSEEK(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info) + unzFile file; + unz_global_info *pglobal_info; +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) + uLong ulDosDate; + tm_unz* ptm; +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unzlocal_GetCurrentFileInfoInternal (file, + pfile_info, + pfile_info_internal, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + unz_file_info_internal *pfile_info_internal; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (ZSEEK(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo (file, + pfile_info, + szFileName, fileNameBufferSize, + extraField, extraFieldBufferSize, + szComment, commentBufferSize) + unzFile file; + unz_file_info *pfile_info; + char *szFileName; + uLong fileNameBufferSize; + void *extraField; + uLong extraFieldBufferSize; + char *szComment; + uLong commentBufferSize; +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (file) + unzFile file; +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (file) + unzFile file; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity) + unzFile file; + const char *szFileName; + int iCaseSensitivity; +{ + unz_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info cur_file_infoSaved; + unz_file_info_internal cur_file_info_internalSaved; + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; // offset in file + uLong num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGoToFilePos(file, file_pos) + unzFile file; + unz_file_pos* file_pos; +{ + unz_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, + poffset_local_extrafield, + psize_local_extrafield) + unz_s* s; + uInt* piSizeVar; + uLong *poffset_local_extrafield; + uInt *psize_local_extrafield; +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password) + unzFile file; + int* method; + int* level; + int raw; + const char* password; +{ + int err=UNZ_OK; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + ALLOC(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && + (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else + if ((s->cur_file_info.compression_method==Z_DEFLATED) && + (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (file) + unzFile file; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (file, password) + unzFile file; + const char* password; +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw) + unzFile file; + int* method; + int* level; + int raw; +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (file, buf, len) + unzFile file; + voidp buf; + unsigned len; +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->read_buffer == NULL) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (file) + unzFile file; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (file,buf,len) + unzFile file; + voidp buf; + unsigned len; +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (file) + unzFile file; +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) + unzFile file; + char *szComment; + uLong uSizeBuf; +{ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern uLong ZEXPORT unzGetOffset (file) + unzFile file; +{ + unz_s* s; + + if (file==NULL) + return 0; + s=(unz_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern int ZEXPORT unzSetOffset (file, pos) + unzFile file; + uLong pos; +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} diff -Nru simgear-2.10.0/simgear/package/unzip.h simgear-3.0.0/simgear/package/unzip.h --- simgear-2.10.0/simgear/package/unzip.h 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/package/unzip.h 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,360 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.01h, December 28th, 2009 + + Copyright (C) 1998-2009 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + + Multi volume ZipFile (span) are not supported. + Encryption compatible with pkzip 2.04g only supported + Old compressions used by old PKZip 1.x are not supported + + + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + 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. + + +*/ + +/* for more info about .ZIP format, see + http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip + http://www.info-zip.org/pub/infozip/doc/ + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip +*/ + +#ifndef _unz_H +#define _unz_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz_H */ diff -Nru simgear-2.10.0/simgear/props/CMakeLists.txt simgear-3.0.0/simgear/props/CMakeLists.txt --- simgear-2.10.0/simgear/props/CMakeLists.txt 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/props/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -3,10 +3,13 @@ set(HEADERS AtomicChangeListener.hxx + condition.hxx + easing_functions.hxx ExtendedPropertyAdapter.hxx PropertyBasedElement.hxx PropertyBasedMgr.hxx - condition.hxx + PropertyInterpolationMgr.hxx + PropertyInterpolator.hxx propertyObject.hxx props.hxx props_io.hxx @@ -17,9 +20,12 @@ set(SOURCES AtomicChangeListener.cxx + condition.cxx + easing_functions.cxx PropertyBasedElement.cxx PropertyBasedMgr.cxx - condition.cxx + PropertyInterpolationMgr.cxx + PropertyInterpolator.cxx propertyObject.cxx props.cxx props_io.cxx @@ -28,11 +34,17 @@ simgear_component(props props "${SOURCES}" "${HEADERS}") if(ENABLE_TESTS) + add_executable(test_props props_test.cxx) -target_link_libraries(test_props SimGearCore) -add_test(test_props ${EXECUTABLE_OUTPUT_PATH}/test_props) +target_link_libraries(test_props ${TEST_LIBS}) +add_test(props ${EXECUTABLE_OUTPUT_PATH}/test_props) add_executable(test_propertyObject propertyObject_test.cxx) -target_link_libraries(test_propertyObject SimGearCore) -add_test(test_propertyObject ${EXECUTABLE_OUTPUT_PATH}/test_propertyObject) +target_link_libraries(test_propertyObject ${TEST_LIBS}) +add_test(propertyObject ${EXECUTABLE_OUTPUT_PATH}/test_propertyObject) + +add_executable(test_easing_functions easing_functions_test.cxx) +target_link_libraries(test_easing_functions ${TEST_LIBS}) +add_test(easing_functions ${EXECUTABLE_OUTPUT_PATH}/test_easing_functions) + endif(ENABLE_TESTS) diff -Nru simgear-2.10.0/simgear/props/condition.cxx simgear-3.0.0/simgear/props/condition.cxx --- simgear-2.10.0/simgear/props/condition.cxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/props/condition.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -22,7 +22,8 @@ using std::istream; using std::ostream; - +using std::string; + /** * Condition for a single property. * @@ -36,6 +37,8 @@ const char * propname ); virtual ~SGPropertyCondition (); virtual bool test () const { return _node->getBoolValue(); } + virtual void collectDependentProperties(std::set& props) const + { props.insert(_node.get()); } private: SGConstPropertyNode_ptr _node; }; @@ -64,6 +67,7 @@ SGNotCondition (SGCondition * condition); virtual ~SGNotCondition (); virtual bool test () const; + virtual void collectDependentProperties(std::set& props) const; private: SGSharedPtr _condition; }; @@ -83,6 +87,7 @@ virtual bool test () const; // transfer pointer ownership virtual void addCondition (SGCondition * condition); + virtual void collectDependentProperties(std::set& props) const; private: std::vector > _conditions; }; @@ -102,6 +107,7 @@ virtual bool test () const; // transfer pointer ownership virtual void addCondition (SGCondition * condition); + virtual void collectDependentProperties(std::set& props) const; private: std::vector > _conditions; }; @@ -136,6 +142,7 @@ void setRightDExpression(SGExpressiond* dexp); void setPrecisionDExpression(SGExpressiond* dexp); + virtual void collectDependentProperties(std::set& props) const; private: Type _type; bool _reverse; @@ -162,7 +169,6 @@ } - //////////////////////////////////////////////////////////////////////// // Implementation of SGPropertyCondition. //////////////////////////////////////////////////////////////////////// @@ -178,7 +184,6 @@ } - //////////////////////////////////////////////////////////////////////// // Implementation of SGNotCondition. //////////////////////////////////////////////////////////////////////// @@ -198,8 +203,12 @@ return !(_condition->test()); } +void +SGNotCondition::collectDependentProperties(std::set& props) const +{ + _condition->collectDependentProperties(props); +} - //////////////////////////////////////////////////////////////////////// // Implementation of SGAndCondition. //////////////////////////////////////////////////////////////////////// @@ -215,8 +224,8 @@ bool SGAndCondition::test () const { - int nConditions = _conditions.size(); - for (int i = 0; i < nConditions; i++) { + for( size_t i = 0; i < _conditions.size(); i++ ) + { if (!_conditions[i]->test()) return false; } @@ -229,8 +238,14 @@ _conditions.push_back(condition); } +void +SGAndCondition::collectDependentProperties(std::set& props) const +{ + for( size_t i = 0; i < _conditions.size(); i++ ) + _conditions[i]->collectDependentProperties(props); +} + - //////////////////////////////////////////////////////////////////////// // Implementation of SGOrCondition. //////////////////////////////////////////////////////////////////////// @@ -246,8 +261,8 @@ bool SGOrCondition::test () const { - int nConditions = _conditions.size(); - for (int i = 0; i < nConditions; i++) { + for( size_t i = 0; i < _conditions.size(); i++ ) + { if (_conditions[i]->test()) return true; } @@ -260,8 +275,14 @@ _conditions.push_back(condition); } +void +SGOrCondition::collectDependentProperties(std::set& props) const +{ + for( size_t i = 0; i < _conditions.size(); i++ ) + _conditions[i]->collectDependentProperties(props); +} + - //////////////////////////////////////////////////////////////////////// // Implementation of SGComparisonCondition. //////////////////////////////////////////////////////////////////////// @@ -427,7 +448,28 @@ { _precision_property = new SGPropertyNode(); _precision_dexp = dexp; -} +} + +void +SGComparisonCondition::collectDependentProperties(std::set& props) const +{ + if (_left_dexp) + _left_dexp->collectDependentProperties(props); + else + props.insert(_left_property); + + if (_right_dexp) + _right_dexp->collectDependentProperties(props); + else + props.insert(_right_property); + + if (_precision_dexp) + _precision_dexp->collectDependentProperties(props); + else if (_precision_property) + props.insert(_precision_property); + +} + //////////////////////////////////////////////////////////////////////// // Read a condition and use it if necessary. //////////////////////////////////////////////////////////////////////// @@ -583,7 +625,6 @@ } - //////////////////////////////////////////////////////////////////////// // Implementation of SGConditional. //////////////////////////////////////////////////////////////////////// @@ -610,7 +651,6 @@ } - // The top-level is always an implicit 'and' group SGCondition * sgReadCondition( SGPropertyNode *prop_root, const SGPropertyNode *node ) diff -Nru simgear-2.10.0/simgear/props/condition.hxx simgear-3.0.0/simgear/props/condition.hxx --- simgear-2.10.0/simgear/props/condition.hxx 2011-09-06 03:21:50.000000000 +0000 +++ simgear-3.0.0/simgear/props/condition.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -10,6 +10,7 @@ #ifndef __SG_CONDITION_HXX #define __SG_CONDITION_HXX +#include #include #include @@ -34,6 +35,7 @@ SGCondition (); virtual ~SGCondition (); virtual bool test () const = 0; + virtual void collectDependentProperties(std::set& props) const { } }; diff -Nru simgear-2.10.0/simgear/props/easing_functions.cxx simgear-3.0.0/simgear/props/easing_functions.cxx --- simgear-2.10.0/simgear/props/easing_functions.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/props/easing_functions.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,231 @@ +///@file +/// Easing functions for property interpolation. +/// +/// Based on easing functions by Robert Penner +/// (http://www.robertpenner.com/easing) +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "easing_functions.hxx" +#include + + +namespace simgear +{ + + /// Simple linear easing. + double easingLinear(double t) + { + return t; + } + + /// http://easings.net/#easeInSine + double easeInSine(double t) + { + return 1 - std::cos(t * M_PI_2); + } + + /// http://easings.net/#easeOutSine + double easeOutSine(double t) + { + return std::sin(t * M_PI_2); + } + + /// http://easings.net/#easeInOutSine + double easeInOutSine(double t) + { + return 0.5 - 0.5 * std::cos(t * M_PI); + } + + template + double easeInOut(double t) + { + if( (t *= 2) < 1 ) + return 0.5 * (*easeIn)(t); + else + return 0.5 + 0.5 * (*easeOut)(t - 1); + } + + template + struct easeOutImpl; + + /// http://easings.net/#easeOutCubic (N = 3) + /// http://easings.net/#easeOutQuint (N = 5) + template + struct easeOutImpl + { + static double calc(double t) + { + return SGMiscd::pow(t - 1) + 1; + } + }; + + /// http://easings.net/#easeOutQuad (N = 2) + /// http://easings.net/#easeOutQuart (N = 4) + template + struct easeOutImpl + { + static double calc(double t) + { + return -SGMiscd::pow(t - 1) + 1; + } + }; + + /// http://easings.net/#easeOutQuad (N = 2) + /// http://easings.net/#easeOutCubic (N = 3) + /// http://easings.net/#easeOutQuart (N = 4) + /// http://easings.net/#easeOutQuint (N = 5) + template + double easeOutPow(double t) + { + return easeOutImpl::calc(t); + } + + /// http://easings.net/#easeInOutQuad (N = 2) + /// http://easings.net/#easeInOutCubic (N = 3) + /// http://easings.net/#easeInOutQuart (N = 4) + /// http://easings.net/#easeInOutQuint (N = 5) + template + double easeInOutPow(double t) + { + return easeInOut<&SGMiscd::pow, &easeOutPow >(t); + } + + /// http://easings.net/#easeInExpo + double easeInExpo(double t) + { + return (t == 0) ? 0 : std::pow(2, 10 * (t - 1)); + } + + /// http://easings.net/#easeOutExpo + double easeOutExpo(double t) + { + return (t == 1) ? 1 : 1 - std::pow(2, -10 * t); + } + + /// http://easings.net/#easeInCirc + double easeInCirc(double t) + { + return 1 - std::sqrt(1 - SGMiscd::pow<2>(t)); + } + + /// http://easings.net/#easeOutCirc + double easeOutCirc(double t) + { + return std::sqrt(1 - SGMiscd::pow<2>(t - 1)); + } + + static const double ease_s = 1.70158; + + /// http://easings.net/#easeInBack + double easeInBack(double t) + { + + return SGMiscd::pow<2>(t) * ((ease_s + 1) * t - ease_s); + } + + /// http://easings.net/#easeOutBack + double easeOutBack(double t) + { + t -= 1; + return SGMiscd::pow<2>(t) * ((ease_s + 1) * t + ease_s) + 1; + } + + /// http://easings.net/#easeOutBack + double easeInElastic(double t) + { + if( t == 0 ) + return 0; + if( t == 1 ) + return 1; + + t -= 1; + const double p = .3; + const double s = p * 0.25; + + return -std::pow(2, 10 * t) * std::sin((t - s) * 2 * M_PI / p); + } + + /// http://easings.net/#easeOutBack + double easeOutElastic(double t) + { + if( t == 0 ) + return 0; + if( t == 1 ) + return 1; + + const double p = .3; + const double s = p * 0.25; + + return std::pow(2, -10 * t) * std::sin((t - s) * 2 * M_PI / p) + 1; + } + + /// http://easings.net/#easeOutBounce + double easeOutBounce(double t) + { + if( t < 1/2.75 ) + return 7.5625 * SGMiscd::pow<2>(t); + else if( t < 2/2.75 ) + return 7.5625 * SGMiscd::pow<2>(t - 1.5/2.75) + .75; + else if( t < 2.5/2.75 ) + return 7.5625 * SGMiscd::pow<2>(t - 2.25/2.75) + .9375; + else + return 7.5625 * SGMiscd::pow<2>(t - 2.625/2.75) + .984375; + } + + /// http://easings.net/#easeInBounce + double easeInBounce(double time) + { + return 1 - easeOutBounce(1 - time); + } + +#define SG_ADD_EASING(name) {#name, &name}, +#define SG_STR(str) #str +#define SG_ADD_EASING_IN_OUT(name)\ + SG_ADD_EASING(easeIn##name)\ + SG_ADD_EASING(easeOut##name)\ + {SG_STR(easeInOut##name), &easeInOut<&easeIn##name, &easeOut##name>}, + + const EasingMapEntry easing_functions[] = { + {"linear", &easingLinear}, + {"swing", &easeInOutSine}, + SG_ADD_EASING_IN_OUT(Sine) + {"easeInQuad", &SGMiscd::pow<2>}, + {"easeInCubic", &SGMiscd::pow<3>}, + {"easeInQuart", &SGMiscd::pow<4>}, + {"easeInQuint", &SGMiscd::pow<5>}, + {"easeOutQuad", &easeOutPow<2>}, + {"easeOutCubic", &easeOutPow<3>}, + {"easeOutQuart", &easeOutPow<4>}, + {"easeOutQuint", &easeOutPow<5>}, + {"easeInOutQuad", &easeInOutPow<2>}, + {"easeInOutCubic",&easeInOutPow<3>}, + {"easeInOutQuart",&easeInOutPow<4>}, + {"easeInOutQuint",&easeInOutPow<5>}, + SG_ADD_EASING_IN_OUT(Expo) + SG_ADD_EASING_IN_OUT(Circ) + SG_ADD_EASING_IN_OUT(Back) + SG_ADD_EASING_IN_OUT(Elastic) + SG_ADD_EASING_IN_OUT(Bounce) + {0, 0} + }; + +#undef SG_ADD_EASING +#undef SG_STR +#undef SG_ADD_EASING_IN_OUT + +} // namespace simgear diff -Nru simgear-2.10.0/simgear/props/easing_functions.hxx simgear-3.0.0/simgear/props/easing_functions.hxx --- simgear-2.10.0/simgear/props/easing_functions.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/props/easing_functions.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,35 @@ +// Easing functions for property interpolation. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_EASING_HXX_ +#define SG_EASING_HXX_ + +namespace simgear +{ + + typedef double (*easing_func_t)(double); + struct EasingMapEntry { const char* name; easing_func_t func; }; + + /** + * List of all available easing functions and their names. + */ + extern const EasingMapEntry easing_functions[]; + +} // namespace simgear + +#endif /* SG_EASING_HXX_ */ diff -Nru simgear-2.10.0/simgear/props/easing_functions_test.cxx simgear-3.0.0/simgear/props/easing_functions_test.cxx --- simgear-2.10.0/simgear/props/easing_functions_test.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/props/easing_functions_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,54 @@ +/* + * easing_functions_test.cxx + * + * Output values of all easing functions for plotting and some simple tests. + * + * Created on: 15.03.2013 + * Author: tom + */ + +#include "easing_functions.hxx" +#include +#include + +#define VERIFY_CLOSE(a, b) \ + if( std::fabs(a - b) > 1e-5 ) \ + { \ + std::cerr << "failed: line " << __LINE__ << ": "\ + << a << " != " << b\ + << std::endl; \ + return 1; \ + } + +int main(int argc, char* argv[]) +{ + using simgear::easing_functions; + + for( double t = 0; t <= 1; t += 1/32. ) + { + if( t == 0 ) + { + for( size_t i = 0; easing_functions[i].name; ++i ) + std::cout << easing_functions[i].name << " "; + std::cout << '\n'; + } + + for( size_t i = 0; easing_functions[i].name; ++i ) + { + double val = (*easing_functions[i].func)(t); + std::cout << val << " "; + + if( t == 0 ) + { + VERIFY_CLOSE(val, 0) + } + else if( t == 1 ) + { + VERIFY_CLOSE(val, 1) + } + } + std::cout << '\n'; + } + + return 0; +} diff -Nru simgear-2.10.0/simgear/props/PropertyBasedElement.cxx simgear-3.0.0/simgear/props/PropertyBasedElement.cxx --- simgear-2.10.0/simgear/props/PropertyBasedElement.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/props/PropertyBasedElement.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -31,9 +31,28 @@ //------------------------------------------------------------------------------ PropertyBasedElement::~PropertyBasedElement() { + onDestroy(); + removeListener(); + } + + //---------------------------------------------------------------------------- + void PropertyBasedElement::removeListener() + { _node->removeChangeListener(this); } + //---------------------------------------------------------------------------- + void PropertyBasedElement::destroy() + { + if( !_node ) + return; + + // TODO check if really not in use anymore + if( _node->getParent() ) + _node->getParent() + ->removeChild(_node->getName(), _node->getIndex(), false); + } + //------------------------------------------------------------------------------ SGConstPropertyNode_ptr PropertyBasedElement::getProps() const { diff -Nru simgear-2.10.0/simgear/props/PropertyBasedElement.hxx simgear-3.0.0/simgear/props/PropertyBasedElement.hxx --- simgear-2.10.0/simgear/props/PropertyBasedElement.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/props/PropertyBasedElement.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -21,6 +21,7 @@ #include +#include #include #include @@ -42,12 +43,45 @@ PropertyBasedElement(SGPropertyNode* node); virtual ~PropertyBasedElement(); + /** + * Remove the property listener of the element. + * + * You will need to call the appropriate methods (#childAdded, + * #childRemoved, #valueChanged) yourself to ensure the element still + * receives the needed events. + */ + void removeListener(); + + /** + * Destroys this element (removes node from property tree) + */ + void destroy(); + virtual void update(double delta_time_sec) = 0; SGConstPropertyNode_ptr getProps() const; SGPropertyNode_ptr getProps(); + template + void set( const std::string& name, + typename boost::call_traits::param_type val ) + { + setValue(_node->getNode(name, true), val); + } + + template + T get( const std::string& name, + typename boost::call_traits::param_type def = T() ) + { + SGPropertyNode const* child = _node->getNode(name); + if( !child ) + return def; + + return getValue(child); + } + virtual void setSelf(const PropertyBasedElementPtr& self); + virtual void onDestroy() {}; protected: diff -Nru simgear-2.10.0/simgear/props/PropertyBasedMgr.cxx simgear-3.0.0/simgear/props/PropertyBasedMgr.cxx --- simgear-2.10.0/simgear/props/PropertyBasedMgr.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/props/PropertyBasedMgr.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -36,6 +36,7 @@ //---------------------------------------------------------------------------- void PropertyBasedMgr::shutdown() { + _props->removeAllChildren(); _props->removeChangeListener(this); } @@ -95,7 +96,7 @@ _name_elements( name_elements ), _element_factory( element_factory ) { - + _props->setAttribute(SGPropertyNode::PRESERVE, true); } //---------------------------------------------------------------------------- @@ -126,6 +127,7 @@ _elements.resize(index + 1); } else if( _elements[index] ) + { SG_LOG ( SG_GENERAL, @@ -133,6 +135,10 @@ _name_elements << "[" << index << "] already exists!" ); + // Give anything holding a reference to this element to release it + _elements[index]->onDestroy(); + } + PropertyBasedElementPtr el = _element_factory(child); el->setSelf( el ); _elements[index] = el; @@ -158,8 +164,11 @@ "can't removed unknown " << _name_elements << "[" << index << "]!" ); else + { // remove the element... + _elements[index]->onDestroy(); _elements[index].reset(); + } } } // namespace simgear diff -Nru simgear-2.10.0/simgear/props/PropertyInterpolationMgr.cxx simgear-3.0.0/simgear/props/PropertyInterpolationMgr.cxx --- simgear-2.10.0/simgear/props/PropertyInterpolationMgr.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/props/PropertyInterpolationMgr.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,255 @@ +// Subsystem that manages interpolation of properties. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "PropertyInterpolationMgr.hxx" +#include "PropertyInterpolator.hxx" +#include "props.hxx" + +#include + +namespace simgear +{ + + //---------------------------------------------------------------------------- + PropertyInterpolationMgr::PropertyInterpolationMgr() + { + addInterpolatorFactory("numeric"); + + for( size_t i = 0; easing_functions[i].name; ++i ) + addEasingFunction + ( + easing_functions[i].name, + easing_functions[i].func + ); + } + + //---------------------------------------------------------------------------- + void PropertyInterpolationMgr::update(double dt) + { + if( _rt_prop ) + dt = _rt_prop->getDoubleValue(); + + for( InterpolatorList::iterator it = _interpolators.begin(); + it != _interpolators.end(); + ++it ) + { + for(double unused_time = dt;;) + { + PropertyInterpolatorRef interp = it->second; + unused_time = interp->update(*it->first, unused_time); + + if( unused_time <= 0.0 ) + // No time left for next animation + break; + + if( interp->_next ) + { + // Step to next animation. Note that we do not invalidate or delete + // the current interpolator to allow for looped animations. + it->second = interp->_next; + } + else + { + // No more animations so just remove it + it = _interpolators.erase(it); + break; + } + } + } + } + + //---------------------------------------------------------------------------- + struct PropertyInterpolationMgr::PredicateIsSameProp + { + public: + PredicateIsSameProp(SGPropertyNode* node): + _node(node) + {} + bool operator()(const PropertyInterpolatorPair& interp) const + { + return interp.first == _node; + } + protected: + SGPropertyNode *_node; + }; + + //---------------------------------------------------------------------------- + PropertyInterpolator* + PropertyInterpolationMgr::createInterpolator( const std::string& type, + const SGPropertyNode& target, + double duration, + const std::string& easing ) + { + InterpolatorFactoryMap::iterator interpolator_factory = + _interpolator_factories.find(type); + if( interpolator_factory == _interpolator_factories.end() ) + { + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "PropertyInterpolationMgr: no factory found for type '" << type << "'" + ); + return 0; + } + + EasingFunctionMap::iterator easing_func = _easing_functions.find(easing); + if( easing_func == _easing_functions.end() ) + { + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "PropertyInterpolationMgr: no such easing '" << type << "'" + ); + return 0; + } + + PropertyInterpolator* interp; + interp = (*interpolator_factory->second)(); + interp->reset(target); + interp->_type = type; + interp->_duration = duration; + interp->_easing = easing_func->second; + + return interp; + } + + //---------------------------------------------------------------------------- + bool PropertyInterpolationMgr::interpolate( SGPropertyNode* prop, + PropertyInterpolatorRef interp ) + { + if( !prop ) + return false; + + // Search for active interpolator on given property + InterpolatorList::iterator it = std::find_if + ( + _interpolators.begin(), + _interpolators.end(), + PredicateIsSameProp(prop) + ); + + if( !interp ) + { + // Without new interpolator just remove old one + if( it != _interpolators.end() ) + _interpolators.erase(it); + return true; + } + + if( it != _interpolators.end() ) + { + // Ensure no circular reference is left + it->second->_next = 0; + + // and now safely replace old interpolator + // TODO maybe cache somewhere for reuse or use allocator? + it->second = interp; + } + else + _interpolators.push_front( std::make_pair(prop, interp) ); + + return true; + } + + //---------------------------------------------------------------------------- + bool PropertyInterpolationMgr::interpolate( SGPropertyNode* prop, + const std::string& type, + const SGPropertyNode& target, + double duration, + const std::string& easing ) + { + return interpolate + ( + prop, + createInterpolator(type, target, duration, easing) + ); + } + + //---------------------------------------------------------------------------- + bool PropertyInterpolationMgr::interpolate( SGPropertyNode* prop, + const std::string& type, + const PropertyList& values, + const double_list& deltas, + const std::string& easing ) + { + if( values.size() != deltas.size() ) + SG_LOG(SG_GENERAL, SG_WARN, "interpolate: sizes do not match"); + + size_t num_values = std::min(values.size(), deltas.size()); + PropertyInterpolatorRef first_interp, cur_interp; + for(size_t i = 0; i < num_values; ++i) + { + assert(values[i]); + + PropertyInterpolator* interp = + createInterpolator(type, *values[i], deltas[i], easing); + + if( !first_interp ) + first_interp = interp; + else + cur_interp->_next = interp; + + cur_interp = interp; + } + + return interpolate(prop, first_interp); + } + + //---------------------------------------------------------------------------- + void PropertyInterpolationMgr::addInterpolatorFactory + ( + const std::string& type, + InterpolatorFactory factory + ) + { + if( _interpolator_factories.find(type) != _interpolator_factories.end() ) + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "PropertyInterpolationMgr: replace existing factor for type " << type + ); + + _interpolator_factories[type] = factory; + } + + //---------------------------------------------------------------------------- + void PropertyInterpolationMgr::addEasingFunction( const std::string& type, + easing_func_t func ) + { + // TODO it's probably time for a generic factory map + if( _easing_functions.find(type) != _easing_functions.end() ) + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "PropertyInterpolationMgr: replace existing easing function " << type + ); + + _easing_functions[type] = func; + } + + //---------------------------------------------------------------------------- + void PropertyInterpolationMgr::setRealtimeProperty(SGPropertyNode* node) + { + _rt_prop = node; + } + +} // namespace simgear diff -Nru simgear-2.10.0/simgear/props/PropertyInterpolationMgr.hxx simgear-3.0.0/simgear/props/PropertyInterpolationMgr.hxx --- simgear-2.10.0/simgear/props/PropertyInterpolationMgr.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/props/PropertyInterpolationMgr.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,147 @@ +// Subsystem that manages interpolation of properties. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_PROPERTY_INTERPOLATION_MGR_HXX_ +#define SG_PROPERTY_INTERPOLATION_MGR_HXX_ + +#include "PropertyInterpolator.hxx" + +#include +#include +#include +#include + +#include + +namespace simgear +{ + + /** + * Subsystem that manages interpolation of properties. + * + * By default the numeric values of the properties are interpolated. For + * example, for strings this is probably not the wanted behavior. For this + * adapter classes can be registered to allow providing specific + * interpolations for certain types of properties. Using the type "color", + * provided by ColorInterpolator, strings containing %CSS colors can also be + * interpolated. + * + * Additionally different functions can be used for easing of the animation. + * By default "linear" (constant animation speed) and "swing" (smooth + * acceleration and deceleration) are available. + */ + class PropertyInterpolationMgr: + public SGSubsystem + { + public: + typedef PropertyInterpolator* (*InterpolatorFactory)(); + + PropertyInterpolationMgr(); + + /** + * Update all active interpolators. + */ + void update(double dt); + + /** + * Create a new property interpolator. + * + * @note To actually use it the interpolator needs to be attached to a + * property using PropertyInterpolationMgr::interpolate. + * + * @param type Type of animation ("numeric", "color", etc.) + * @param target Property containing target value + * @param duration Duration if the animation (in seconds) + * @param easing Type of easing ("linear", "swing", etc.) + */ + PropertyInterpolator* + createInterpolator( const std::string& type, + const SGPropertyNode& target, + double duration, + const std::string& easing ); + + /** + * Add animation of the given property from its current value to the + * target value of the interpolator. If no interpolator is given any + * existing animation of the given property is aborted. + * + * @param prop Property to be interpolated + * @param interp Interpolator used for interpolation + */ + bool interpolate( SGPropertyNode* prop, + PropertyInterpolatorRef interp = 0 ); + + bool interpolate( SGPropertyNode* prop, + const std::string& type, + const SGPropertyNode& target, + double duration, + const std::string& easing ); + + bool interpolate( SGPropertyNode* prop, + const std::string& type, + const PropertyList& values, + const double_list& deltas, + const std::string& easing ); + + /** + * Register factory for interpolation type. + */ + void addInterpolatorFactory( const std::string& type, + InterpolatorFactory factory ); + template + void addInterpolatorFactory(const std::string& type) + { + addInterpolatorFactory + ( + type, + &simgear::make_new_derived + ); + } + + /** + * Register easing function. + */ + void addEasingFunction(const std::string& type, easing_func_t func); + + /** + * Set property containing real time delta (not sim time) + * + * TODO better pass both deltas to all update methods... + */ + void setRealtimeProperty(SGPropertyNode* node); + + protected: + + typedef std::map InterpolatorFactoryMap; + typedef std::map EasingFunctionMap; + typedef std::pair< SGPropertyNode*, + PropertyInterpolatorRef > PropertyInterpolatorPair; + typedef std::list InterpolatorList; + + struct PredicateIsSameProp; + + InterpolatorFactoryMap _interpolator_factories; + EasingFunctionMap _easing_functions; + InterpolatorList _interpolators; + + SGPropertyNode_ptr _rt_prop; + }; + +} // namespace simgear + +#endif /* SG_PROPERTY_INTERPOLATION_MGR_HXX_ */ diff -Nru simgear-2.10.0/simgear/props/PropertyInterpolator.cxx simgear-3.0.0/simgear/props/PropertyInterpolator.cxx --- simgear-2.10.0/simgear/props/PropertyInterpolator.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/props/PropertyInterpolator.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,104 @@ +// Adapter for interpolating different types of properties. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "PropertyInterpolator.hxx" +#include "props.hxx" + +#include +#include + +namespace simgear +{ + + //---------------------------------------------------------------------------- + PropertyInterpolator::~PropertyInterpolator() + { + + } + + //---------------------------------------------------------------------------- + void PropertyInterpolator::reset(const SGPropertyNode& target) + { + _cur_t = 0; + setTarget(target); + } + + //---------------------------------------------------------------------------- + void PropertyInterpolator::setEasingFunction(easing_func_t easing) + { + _easing = easing ? easing : easing_functions[0].func; + } + + //---------------------------------------------------------------------------- + double PropertyInterpolator::update(SGPropertyNode& prop, double dt) + { + if( _cur_t == 0 ) + init(prop); + + _cur_t += dt / _duration; + + double unused = _cur_t - 1; + if( unused > 0 ) + _cur_t = 1; + + write(prop, _easing(_cur_t) ); + + if( _cur_t == 1 ) + // Reset timer to allow animation to be run again. + _cur_t = 0; + + return unused; + } + + //---------------------------------------------------------------------------- + PropertyInterpolator::PropertyInterpolator(): + _duration(1), + _cur_t(0) + { + setEasingFunction(0); + } + + //---------------------------------------------------------------------------- + void NumericInterpolator::setTarget(const SGPropertyNode& target) + { + _end = target.getDoubleValue(); + } + + //---------------------------------------------------------------------------- + void NumericInterpolator::init(const SGPropertyNode& prop) + { + // If unable to get start value, immediately change to target value + double value_start = prop.getType() == props::NONE + ? _end + : prop.getDoubleValue(); + + _diff = _end - value_start; + } + + //---------------------------------------------------------------------------- + void NumericInterpolator::write(SGPropertyNode& prop, double t) + { + double cur = _end - (1 - t) * _diff; + + if( prop.getType() == props::INT || prop.getType() == props::LONG ) + prop.setLongValue( static_cast(std::floor(cur + 0.5)) ); + else + prop.setDoubleValue(cur); + } + +} // namespace simgear diff -Nru simgear-2.10.0/simgear/props/PropertyInterpolator.hxx simgear-3.0.0/simgear/props/PropertyInterpolator.hxx --- simgear-2.10.0/simgear/props/PropertyInterpolator.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/props/PropertyInterpolator.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,101 @@ +// Adapter for interpolating different types of properties. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_PROPERTY_INTERPOLATOR_HXX_ +#define SG_PROPERTY_INTERPOLATOR_HXX_ + +#include "easing_functions.hxx" +#include "propsfwd.hxx" + +#include +#include +#include + +#include + +namespace simgear +{ + + class PropertyInterpolator; + typedef SGSharedPtr PropertyInterpolatorRef; + + /** + * Base class for interpolating different types of properties over time. + */ + class PropertyInterpolator: + public SGReferenced + { + public: + virtual ~PropertyInterpolator(); + + /** + * Resets animation timer to zero and prepares for interpolation to new + * target value. + */ + void reset(const SGPropertyNode& target); + + /** + * Set easing function to be used for interpolation. + */ + void setEasingFunction(easing_func_t easing); + + /** + * Calculate an animation step. + * + * @param prop Property being animated + * @param dt Current frame duration + * @return Time not used by the animation (>= 0 if animation has finished, + * else time is negative indicating the remaining time until + * finished) + */ + double update(SGPropertyNode& prop, double dt); + + const std::string& getType() const { return _type; } + + protected: + friend class PropertyInterpolationMgr; + + std::string _type; + easing_func_t _easing; + PropertyInterpolatorRef _next; + double _duration, + _cur_t; + + PropertyInterpolator(); + + virtual void setTarget(const SGPropertyNode& target) = 0; + virtual void init(const SGPropertyNode& prop) = 0; + virtual void write(SGPropertyNode& prop, double t) = 0; + }; + + class NumericInterpolator: + public PropertyInterpolator + { + protected: + double _end, + _diff; + + virtual void setTarget(const SGPropertyNode& target); + virtual void init(const SGPropertyNode& prop); + virtual void write(SGPropertyNode& prop, double t); + }; + +} // namespace simgear + + +#endif /* SG_PROPERTY_INTERPOLATOR_HXX_ */ diff -Nru simgear-2.10.0/simgear/props/propertyObject.cxx simgear-3.0.0/simgear/props/propertyObject.cxx --- simgear-2.10.0/simgear/props/propertyObject.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/props/propertyObject.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -66,15 +66,17 @@ return _prop; } - SGPropertyNode* r = _prop ? _prop : static_defaultRoot; - _prop = r->getNode(_path, aCreate); + SGPropertyNode *r = _prop ? _prop : static_defaultRoot, + *prop = r->getNode(_path, aCreate); - if (_prop) { - // resolve worked, we will cache from now on, so clear _path + if( prop ) + { + // resolve worked, we will cache from now on, so clear _path and cache prop _path = NULL; + _prop = prop; } - return _prop; + return prop; } SGPropertyNode* PropertyObjectBase::getOrThrow() const diff -Nru simgear-2.10.0/simgear/props/propertyObject.hxx simgear-3.0.0/simgear/props/propertyObject.hxx --- simgear-2.10.0/simgear/props/propertyObject.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/props/propertyObject.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -59,19 +59,20 @@ class PropertyObject : PropertyObjectBase { public: - PropertyObject(); + PropertyObject() + {} /** * Create from path relative to the default root, and option default value */ - PropertyObject(const char* aChild) : + explicit PropertyObject(const char* aChild) : PropertyObjectBase(aChild) { } /** * Create from a node, with optional relative path */ - PropertyObject(SGPropertyNode* aNode, const char* aChild = NULL) : + explicit PropertyObject(SGPropertyNode* aNode, const char* aChild = NULL) : PropertyObjectBase(aNode, aChild) { @@ -114,10 +115,9 @@ T operator=(const T& aValue) { SGPropertyNode* n = PropertyObjectBase::node(true); - if (!n) { + if( !n ) return aValue; - } - + n->setValue(aValue); return aValue; } @@ -157,13 +157,13 @@ class PropertyObject : PropertyObjectBase { public: - PropertyObject(const char* aChild) : + explicit PropertyObject(const char* aChild) : PropertyObjectBase(aChild) { } - PropertyObject(SGPropertyNode* aNode, const char* aChild = NULL) : + explicit PropertyObject(SGPropertyNode* aNode, const char* aChild = NULL) : PropertyObjectBase(aNode, aChild) { diff -Nru simgear-2.10.0/simgear/props/propertyObject_test.cxx simgear-3.0.0/simgear/props/propertyObject_test.cxx --- simgear-2.10.0/simgear/props/propertyObject_test.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/props/propertyObject_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -14,6 +14,7 @@ #include #include #include +#include #include "propertyObject.hxx" diff -Nru simgear-2.10.0/simgear/props/props.cxx simgear-3.0.0/simgear/props/props.cxx --- simgear-2.10.0/simgear/props/props.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/props/props.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -11,6 +11,7 @@ #endif #include "props.hxx" +#include "PropertyInterpolationMgr.hxx" #include "vectorPropTemplates.hxx" #include @@ -1074,6 +1075,21 @@ return children; } +void +SGPropertyNode::removeAllChildren() +{ + for(unsigned i = 0; i < _children.size(); ++i) + { + SGPropertyNode_ptr& node = _children[i]; + node->_parent = 0; + node->setAttribute(REMOVED, true); + node->clearValue(); + fireChildRemoved(node); + } + + _children.clear(); +} + string SGPropertyNode::getDisplayName (bool simplify) const { @@ -1654,6 +1670,52 @@ return result; } +//------------------------------------------------------------------------------ +bool SGPropertyNode::interpolate( const std::string& type, + const SGPropertyNode& target, + double duration, + const std::string& easing ) +{ + if( !_interpolation_mgr ) + { + SG_LOG(SG_GENERAL, SG_WARN, "No property interpolator available"); + + // no interpolation possible -> set to target immediately + setUnspecifiedValue( target.getStringValue() ); + return false; + } + + return _interpolation_mgr->interpolate(this, type, target, duration, easing); +} + +//------------------------------------------------------------------------------ +bool SGPropertyNode::interpolate( const std::string& type, + const PropertyList& values, + const double_list& deltas, + const std::string& easing ) +{ + if( !_interpolation_mgr ) + { + SG_LOG(SG_GENERAL, SG_WARN, "No property interpolator available"); + + // no interpolation possible -> set to last value immediately + if( !values.empty() ) + setUnspecifiedValue(values.back()->getStringValue()); + return false; + } + + return _interpolation_mgr->interpolate(this, type, values, deltas, easing); +} + +//------------------------------------------------------------------------------ +void SGPropertyNode::setInterpolationMgr(simgear::PropertyInterpolationMgr* mgr) +{ + _interpolation_mgr = mgr; +} + +simgear::PropertyInterpolationMgr* SGPropertyNode::_interpolation_mgr = 0; + +//------------------------------------------------------------------------------ std::ostream& SGPropertyNode::printOn(std::ostream& stream) const { if (!getAttribute(READ)) diff -Nru simgear-2.10.0/simgear/props/props.hxx simgear-3.0.0/simgear/props/props.hxx --- simgear-2.10.0/simgear/props/props.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/props/props.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -20,8 +20,10 @@ #include #include #include +#include #include +#include #if PROPS_STANDALONE #else @@ -31,6 +33,7 @@ #include +#include #include #include @@ -39,6 +42,9 @@ namespace simgear { + + class PropertyInterpolationMgr; + template std::istream& readFrom(std::istream& stream, T& result) { @@ -725,6 +731,7 @@ * whether the property should normally be saved and restored.

*/ enum Attribute { + NO_ATTR = 0, READ = 1, WRITE = 2, ARCHIVE = 4, @@ -904,6 +911,7 @@ simgear::PropertyList getChildren (const std::string& name) const { return getChildren(name.c_str()); } + // TODO do we need the removeXXX methods to return the deleted nodes? /** * Remove child by position. */ @@ -935,6 +943,11 @@ bool keep = true) { return removeChildren(name.c_str(), keep); } + /** + * Remove all children (does not change the value of the node) + */ + void removeAllChildren(); + // // Alias support. // @@ -1238,6 +1251,54 @@ } /** + * Set relative node to given value and afterwards make read only. + * + * @param relative_path Path to node + * @param value Value to set + * + * @return whether value could be set + */ + template + bool setValueReadOnly(const std::string& relative_path, const T& value) + { + SGPropertyNode* node = getNode(relative_path, true); + bool ret = node->setValue(value); + node->setAttributes(READ); + return ret; + } + + /** + * Interpolate current value to target value within given time. + * + * @param type Type of interpolation ("numeric", "color", etc.) + * @param target Node containing target value + * @param duration Duration of interpolation (in seconds) + * @param easing Easing function (http://easings.net/) + */ + bool interpolate( const std::string& type, + const SGPropertyNode& target, + double duration = 0.6, + const std::string& easing = "swing" ); + + /** + * Interpolate current value to a series of values within given durations. + * + * @param type Type of interpolation ("numeric", "color", etc.) + * @param values Nodes containing intermediate and target values + * @param duration Durations for each interpolation step (in seconds) + * @param easing Easing function (http://easings.net/) + */ + bool interpolate( const std::string& type, + const simgear::PropertyList& values, + const double_list& deltas, + const std::string& easing = "swing" ); + + /** + * Set the interpolation manager used by the interpolate methods. + */ + static void setInterpolationMgr(simgear::PropertyInterpolationMgr* mgr); + + /** * Print the value of the property to a stream. */ std::ostream& printOn(std::ostream& stream) const; @@ -1650,6 +1711,8 @@ template SGPropertyNode (Itr begin, Itr end, int index, SGPropertyNode * parent); + static simgear::PropertyInterpolationMgr* _interpolation_mgr; + private: // Get the raw value @@ -1730,7 +1793,8 @@ // Convenience functions for use in templates template -T getValue(const SGPropertyNode*); +typename boost::disable_if, T>::type +getValue(const SGPropertyNode*); template<> inline bool getValue(const SGPropertyNode* node) { return node->getBoolValue(); } @@ -1759,6 +1823,58 @@ return node->getStringValue (); } +template<> +inline std::string getValue(const SGPropertyNode* node) +{ + return node->getStringValue(); +} + +namespace simgear +{ + /** + * Default trait for extracting enum values from SGPropertyNode. Create your + * own specialization for specific enum types to enable validation of values. + */ + template + struct enum_traits + { + /** + * Typename of the enum + */ + static const char* name() { return typeid(T).name(); } + + /** + * @return Default value (will be used if validation fails) + */ + static T defVal() { return T(); } + + /** + * @return Whether the given integer value has an enum value defined + */ + static bool validate(int) { return true; } + }; +} // namespace simgear + +/** Extract enum from SGPropertyNode */ +template +inline typename boost::enable_if, T>::type +getValue(const SGPropertyNode* node) +{ + typedef simgear::enum_traits Traits; + int val = node->getIntValue(); + if( !Traits::validate(val) ) + { + SG_LOG + ( + SG_GENERAL, + SG_WARN, + "Invalid value for enum (" << Traits::name() << ", val = " << val << ")" + ); + return Traits::defVal(); + } + return static_cast(node->getIntValue()); +} + inline bool setValue(SGPropertyNode* node, bool value) { return node->setBoolValue(value); @@ -1996,6 +2112,13 @@ { _property->addChangeListener(this,initial); } + + SGPropertyChangeCallback(const SGPropertyChangeCallback& other) : + _obj(other._obj), _callback(other._callback), _property(other._property) + { + _property->addChangeListener(this,false); + } + virtual ~SGPropertyChangeCallback() { _property->removeChangeListener(this); diff -Nru simgear-2.10.0/simgear/props/props_io.cxx simgear-3.0.0/simgear/props/props_io.cxx --- simgear-2.10.0/simgear/props/props_io.cxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/props/props_io.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -138,7 +138,8 @@ * Check a yes/no flag, with default. */ static bool -checkFlag (const char * flag, bool defaultState = true) +checkFlag (const char * flag, const sg_location& location, + bool defaultState = true) { if (flag == 0) return defaultState; @@ -151,7 +152,7 @@ message += flag; message += '\''; // FIXME: add location info - throw sg_io_exception(message, "SimGear Property Reader"); + throw sg_io_exception(message, location, "SimGear Property Reader"); } } @@ -159,13 +160,14 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts) { const char * attval; + const sg_location location(getPath(), getLine(), getColumn()); if (_level == 0) { if (strcmp(name, "PropertyList")) { string message = "Root element name is "; message += name; message += "; expected PropertyList"; - throw sg_io_exception(message, "SimGear Property Reader"); + throw sg_io_exception(message, location, "SimGear Property Reader"); } // Check for an include. @@ -175,7 +177,10 @@ SGPath path = simgear::ResourceManager::instance()->findPath(attval, SGPath(_base).dir()); if (path.isNull()) { - throw sg_io_exception("Cannot open file", sg_location(attval)); + string message ="Cannot open file "; + message += attval; + throw sg_io_exception(message, location, + "SimGear Property Reader"); } readProperties(path.str(), _root, 0, _extended); } catch (sg_io_exception &e) { @@ -204,7 +209,7 @@ SGPropertyNode * node = st.node->getChild(strName, index, true); if (!node->getAttribute(SGPropertyNode::WRITE)) { SG_LOG(SG_INPUT, SG_ALERT, "Not overwriting write-protected property " - << node->getPath(true)); + << node->getPath(true) << "\n at " << location.asString()); node = &null; } @@ -214,32 +219,33 @@ int mode = _default_mode; attval = atts.getValue("read"); - if (checkFlag(attval, true)) + if (checkFlag(attval, location, true)) mode |= SGPropertyNode::READ; attval = atts.getValue("write"); - if (checkFlag(attval, true)) + if (checkFlag(attval, location, true)) mode |= SGPropertyNode::WRITE; attval = atts.getValue("archive"); - if (checkFlag(attval, false)) + if (checkFlag(attval, location, false)) mode |= SGPropertyNode::ARCHIVE; attval = atts.getValue("trace-read"); - if (checkFlag(attval, false)) + if (checkFlag(attval, location, false)) mode |= SGPropertyNode::TRACE_READ; attval = atts.getValue("trace-write"); - if (checkFlag(attval, false)) + if (checkFlag(attval, location, false)) mode |= SGPropertyNode::TRACE_WRITE; attval = atts.getValue("userarchive"); - if (checkFlag(attval, false)) + if (checkFlag(attval, location, false)) mode |= SGPropertyNode::USERARCHIVE; attval = atts.getValue("preserve"); - if (checkFlag(attval, false)) + if (checkFlag(attval, location, false)) mode |= SGPropertyNode::PRESERVE; // Check for an alias. attval = atts.getValue("alias"); if (attval != 0) { if (!node->alias(attval)) - SG_LOG(SG_INPUT, SG_ALERT, "Failed to set alias to " << attval); + SG_LOG(SG_INPUT, SG_ALERT, "Failed to set alias to " << attval + << "\n at " << location.asString()); } // Check for an include. @@ -250,7 +256,10 @@ SGPath path = simgear::ResourceManager::instance()->findPath(attval, SGPath(_base).dir()); if (path.isNull()) { - throw sg_io_exception("Cannot open file", sg_location(attval)); + string message ="Cannot open file "; + message += attval; + throw sg_io_exception(message, location, + "SimGear Property Reader"); } readProperties(path.str(), node, 0, _extended); } catch (sg_io_exception &e) { @@ -258,7 +267,7 @@ } attval = atts.getValue("omit-node"); - omit = checkFlag(attval, false); + omit = checkFlag(attval, location, false); } const char *type = atts.getValue("type"); @@ -276,6 +285,7 @@ { State &st = state(); bool ret; + const sg_location location(getPath(), getLine(), getColumn()); // If there are no children and it's // not an alias, then it's a leaf value. @@ -310,12 +320,13 @@ message += st.type; message += '\''; // FIXME: add location information - throw sg_io_exception(message, "SimGear Property Reader"); + throw sg_io_exception(message, location, "SimGear Property Reader"); } if (!ret) SG_LOG(SG_INPUT, SG_ALERT, "readProperties: Failed to set " << st.node->getPath() << " to value \"" - << _data << "\" with type " << st.type); + << _data << "\" with type " << st.type << "\n at " + << location.asString()); } // Set the access-mode attributes now, @@ -605,7 +616,7 @@ bool write_all, SGPropertyNode::Attribute archive_flag) { SGPath path(file.c_str()); - path.create_dir(0777); + path.create_dir(0755); ofstream output(file.c_str()); if (output.good()) { @@ -629,6 +640,64 @@ //////////////////////////////////////////////////////////////////////// +bool +copyPropertyValue(const SGPropertyNode *in, SGPropertyNode *out) +{ + using namespace simgear; + bool retval = true; + + if (!in->hasValue()) { + return true; + } + + switch (in->getType()) { + case props::BOOL: + if (!out->setBoolValue(in->getBoolValue())) + retval = false; + break; + case props::INT: + if (!out->setIntValue(in->getIntValue())) + retval = false; + break; + case props::LONG: + if (!out->setLongValue(in->getLongValue())) + retval = false; + break; + case props::FLOAT: + if (!out->setFloatValue(in->getFloatValue())) + retval = false; + break; + case props::DOUBLE: + if (!out->setDoubleValue(in->getDoubleValue())) + retval = false; + break; + case props::STRING: + if (!out->setStringValue(in->getStringValue())) + retval = false; + break; + case props::UNSPECIFIED: + if (!out->setUnspecifiedValue(in->getStringValue())) + retval = false; + break; + case props::VEC3D: + if (!out->setValue(in->getValue())) + retval = false; + break; + case props::VEC4D: + if (!out->setValue(in->getValue())) + retval = false; + break; + default: + if (in->isAlias()) + break; + string message = "Unknown internal SGPropertyNode type"; + message += in->getType(); + throw sg_error(message, "SimGear Property Reader"); + } + + return retval; +} + /** * Copy one property tree to another. * @@ -646,57 +715,11 @@ int attr_value, int attr_mask) { using namespace simgear; - bool retval = true; - - // First, copy the actual value, - // if any. - if (in->hasValue()) { - switch (in->getType()) { - case props::BOOL: - if (!out->setBoolValue(in->getBoolValue())) - retval = false; - break; - case props::INT: - if (!out->setIntValue(in->getIntValue())) - retval = false; - break; - case props::LONG: - if (!out->setLongValue(in->getLongValue())) - retval = false; - break; - case props::FLOAT: - if (!out->setFloatValue(in->getFloatValue())) - retval = false; - break; - case props::DOUBLE: - if (!out->setDoubleValue(in->getDoubleValue())) - retval = false; - break; - case props::STRING: - if (!out->setStringValue(in->getStringValue())) - retval = false; - break; - case props::UNSPECIFIED: - if (!out->setUnspecifiedValue(in->getStringValue())) - retval = false; - break; - case props::VEC3D: - if (!out->setValue(in->getValue())) - retval = false; - break; - case props::VEC4D: - if (!out->setValue(in->getValue())) - retval = false; - break; - default: - if (in->isAlias()) - break; - string message = "Unknown internal SGPropertyNode type"; - message += in->getType(); - throw sg_error(message, "SimGear Property Reader"); - } + bool retval = copyPropertyValue(in, out); + if (!retval) { + return false; } - + // copy the attributes. out->setAttributes( in->getAttributes() ); @@ -737,4 +760,41 @@ return retval; } + +bool +copyPropertiesWithAttribute(const SGPropertyNode *in, SGPropertyNode *out, + SGPropertyNode::Attribute attr) +{ + bool retval = copyPropertyValue(in, out); + if (!retval) { + return false; + } + out->setAttributes( in->getAttributes() ); + + // if attribute is set directly on this node, we don't require it on + // descendent nodes. (Allows setting an attribute on an entire sub-tree + // of nodes) + if ((attr != SGPropertyNode::NO_ATTR) && out->getAttribute(attr)) { + attr = SGPropertyNode::NO_ATTR; + } + + int nChildren = in->nChildren(); + for (int i = 0; i < nChildren; i++) { + const SGPropertyNode* in_child = in->getChild(i); + if ((attr != SGPropertyNode::NO_ATTR) && !isArchivable(in_child, attr)) + continue; + + SGPropertyNode* out_child = out->getChild(in_child->getNameString(), + in_child->getIndex(), + true); + + bool ok = copyPropertiesWithAttribute(in_child, out_child, attr); + if (!ok) { + return false; + } + }// of children iteration + + return true; +} + // end of props_io.cxx diff -Nru simgear-2.10.0/simgear/props/props_io.hxx simgear-3.0.0/simgear/props/props_io.hxx --- simgear-2.10.0/simgear/props/props_io.hxx 2011-09-06 03:21:50.000000000 +0000 +++ simgear-3.0.0/simgear/props/props_io.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -65,6 +65,9 @@ int attr_value=0, int attr_mask=0); +bool copyPropertiesWithAttribute(const SGPropertyNode *in, SGPropertyNode *out, + SGPropertyNode::Attribute attr); + #endif // __PROPS_IO_HXX // end of props_io.hxx diff -Nru simgear-2.10.0/simgear/props/props_test.cxx simgear-3.0.0/simgear/props/props_test.cxx --- simgear-2.10.0/simgear/props/props_test.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/props/props_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -19,7 +19,7 @@ using std::endl; - + //////////////////////////////////////////////////////////////////////// // Sample object. //////////////////////////////////////////////////////////////////////// @@ -38,7 +38,7 @@ }; - + //////////////////////////////////////////////////////////////////////// // Sample function. //////////////////////////////////////////////////////////////////////// @@ -48,7 +48,7 @@ static double getNum (int index) { return 1.0 / index; } - + //////////////////////////////////////////////////////////////////////// // Show a value. //////////////////////////////////////////////////////////////////////// @@ -64,7 +64,7 @@ } - + //////////////////////////////////////////////////////////////////////// // Test individual values. //////////////////////////////////////////////////////////////////////// @@ -270,7 +270,7 @@ } - + //////////////////////////////////////////////////////////////////////// // Check property nodes. //////////////////////////////////////////////////////////////////////// diff -Nru simgear-2.10.0/simgear/props/tiedpropertylist.hxx simgear-3.0.0/simgear/props/tiedpropertylist.hxx --- simgear-2.10.0/simgear/props/tiedpropertylist.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/props/tiedpropertylist.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -37,11 +37,11 @@ virtual ~TiedPropertyList() { _root = 0; - if (size()>0) + if (! empty()) { SG_LOG(SG_GENERAL, SG_ALERT, "Detected properties with dangling ties. Use 'Untie' before removing a TiedPropertyList."); // running debug mode: go, fix it! - assert(size() == 0); + assert(empty()); } } @@ -124,7 +124,7 @@ } void Untie() { - while( size() > 0 ) { + while( ! empty() ) { SG_LOG( SG_GENERAL, SG_DEBUG, "untie of " << back()->getPath() ); back()->untie(); pop_back(); diff -Nru simgear-2.10.0/simgear/scene/material/CMakeLists.txt simgear-3.0.0/simgear/scene/material/CMakeLists.txt --- simgear-2.10.0/simgear/scene/material/CMakeLists.txt 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -3,7 +3,6 @@ EffectBuilder.hxx EffectCullVisitor.hxx EffectGeode.hxx - GLPredicate.hxx Pass.hxx Technique.hxx TextureBuilder.hxx @@ -11,6 +10,7 @@ matlib.hxx matmodel.hxx mipmap.hxx + parseBlendFunc.hxx ) set(SOURCES @@ -18,7 +18,6 @@ EffectBuilder.cxx EffectCullVisitor.cxx EffectGeode.cxx - GLPredicate.cxx Pass.cxx Technique.cxx TextureBuilder.cxx @@ -27,7 +26,16 @@ matlib.cxx matmodel.cxx mipmap.cxx + parseBlendFunc.cxx ) simgear_scene_component(material scene/material "${SOURCES}" "${HEADERS}") + +if(ENABLE_TESTS) + +add_executable(test_parseBlendFunc parseBlendFunc_test.cxx ) +add_test(parseBlendFunc ${EXECUTABLE_OUTPUT_PATH}/test_parseBlendFunc) +target_link_libraries(test_parseBlendFunc ${TEST_LIBS} ${OPENSCENEGRAPH_LIBRARIES}) + +endif(ENABLE_TESTS) \ No newline at end of file diff -Nru simgear-2.10.0/simgear/scene/material/EffectBuilder.hxx simgear-3.0.0/simgear/scene/material/EffectBuilder.hxx --- simgear-2.10.0/simgear/scene/material/EffectBuilder.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/EffectBuilder.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -316,7 +316,7 @@ PropertyList useProps = prop->getChildren("use"); if (useProps.size() == 1) { string parentName = useProps[0]->getStringValue(); - if (parentName.size() == 0 || parentName[0] != '/') + if (parentName.empty() || parentName[0] != '/') parentName = options->getPropertyNode()->getPath() + "/" + parentName; if (parentName[parentName.size() - 1] != '/') parentName.append("/"); @@ -331,7 +331,7 @@ itr != end; ++itr) { string childName = (*itr)->getStringValue(); - if (childName.size() == 0 || childName[0] != '/') + if (childName.empty() || childName[0] != '/') result.push_back(parentName + childName); else result.push_back(childName); diff -Nru simgear-2.10.0/simgear/scene/material/Effect.cxx simgear-3.0.0/simgear/scene/material/Effect.cxx --- simgear-2.10.0/simgear/scene/material/Effect.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/Effect.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -24,6 +24,7 @@ #include "Technique.hxx" #include "Pass.hxx" #include "TextureBuilder.hxx" +#include "parseBlendFunc.hxx" #include #include @@ -453,58 +454,16 @@ pass->setMode(GL_BLEND, StateAttribute::OFF); return; } - const SGPropertyNode* psource - = getEffectPropertyChild(effect, prop, "source"); - const SGPropertyNode* pdestination - = getEffectPropertyChild(effect, prop, "destination"); - const SGPropertyNode* psourceRGB - = getEffectPropertyChild(effect, prop, "source-rgb"); - const SGPropertyNode* psourceAlpha - = getEffectPropertyChild(effect, prop, "source-alpha"); - const SGPropertyNode* pdestRGB - = getEffectPropertyChild(effect, prop, "destination-rgb"); - const SGPropertyNode* pdestAlpha - = getEffectPropertyChild(effect, prop, "destination-alpha"); - BlendFunc::BlendFuncMode sourceMode = BlendFunc::ONE; - BlendFunc::BlendFuncMode destMode = BlendFunc::ZERO; - if (psource) - findAttr(blendFuncModes, psource, sourceMode); - if (pdestination) - findAttr(blendFuncModes, pdestination, destMode); - if (psource && pdestination - && !(psourceRGB || psourceAlpha || pdestRGB || pdestAlpha) - && sourceMode == BlendFunc::SRC_ALPHA - && destMode == BlendFunc::ONE_MINUS_SRC_ALPHA) { - pass->setAttributeAndModes(StateAttributeFactory::instance() - ->getStandardBlendFunc()); - return; - } - BlendFunc* blendFunc = new BlendFunc; - if (psource) - blendFunc->setSource(sourceMode); - if (pdestination) - blendFunc->setDestination(destMode); - if (psourceRGB) { - BlendFunc::BlendFuncMode sourceRGBMode; - findAttr(blendFuncModes, psourceRGB, sourceRGBMode); - blendFunc->setSourceRGB(sourceRGBMode); - } - if (pdestRGB) { - BlendFunc::BlendFuncMode destRGBMode; - findAttr(blendFuncModes, pdestRGB, destRGBMode); - blendFunc->setDestinationRGB(destRGBMode); - } - if (psourceAlpha) { - BlendFunc::BlendFuncMode sourceAlphaMode; - findAttr(blendFuncModes, psourceAlpha, sourceAlphaMode); - blendFunc->setSourceAlpha(sourceAlphaMode); - } - if (pdestAlpha) { - BlendFunc::BlendFuncMode destAlphaMode; - findAttr(blendFuncModes, pdestAlpha, destAlphaMode); - blendFunc->setDestinationAlpha(destAlphaMode); - } - pass->setAttributeAndModes(blendFunc); + + parseBlendFunc( + pass, + getEffectPropertyChild(effect, prop, "source"), + getEffectPropertyChild(effect, prop, "destination"), + getEffectPropertyChild(effect, prop, "source-rgb"), + getEffectPropertyChild(effect, prop, "destination-rgb"), + getEffectPropertyChild(effect, prop, "source-alpha"), + getEffectPropertyChild(effect, prop, "destination-alpha") + ); } }; @@ -1399,14 +1358,25 @@ class PropertyExpression : public SGExpression { public: - PropertyExpression(SGPropertyNode* pnode) : _pnode(pnode) {} + PropertyExpression(SGPropertyNode* pnode) : _pnode(pnode), _listener(NULL) {} + + ~PropertyExpression() + { + delete _listener; + } void eval(T& value, const expression::Binding*) const { value = _pnode->getValue(); } + + void setListener(SGPropertyChangeListener* l) + { + _listener = l; + } protected: SGPropertyNode_ptr _pnode; + SGPropertyChangeListener* _listener; }; class EffectPropertyListener : public SGPropertyChangeListener @@ -1419,6 +1389,9 @@ if (_tniq.valid()) _tniq->refreshValidity(); } + + virtual ~EffectPropertyListener() { } + protected: osg::observer_ptr _tniq; }; @@ -1432,9 +1405,12 @@ PropertyExpression* pexp = new PropertyExpression(pnode); TechniquePredParser* predParser = dynamic_cast(parser); - if (predParser) - pnode->addChangeListener(new EffectPropertyListener(predParser - ->getTechnique())); + if (predParser) { + EffectPropertyListener* l = new EffectPropertyListener(predParser + ->getTechnique()); + pexp->setListener(l); + pnode->addChangeListener(l); + } return pexp; } diff -Nru simgear-2.10.0/simgear/scene/material/EffectGeode.cxx simgear-3.0.0/simgear/scene/material/EffectGeode.cxx --- simgear-2.10.0/simgear/scene/material/EffectGeode.cxx 2011-06-29 14:58:56.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/EffectGeode.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -22,6 +22,8 @@ #include "Effect.hxx" #include "Technique.hxx" +#include + #include #include @@ -80,15 +82,27 @@ int n = _effect->getGenerator(Effect::TANGENT); tsg->generate(geometry, 0); // 0 is normal_unit, but I have no idea what that is! if (n != -1 && !geometry->getVertexAttribArray(n)) - geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getTangentArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); +#if OSG_MIN_VERSION_REQUIRED(3,1,8) + geometry->setVertexAttribArray(n, tsg->getTangentArray(), osg::Array::BIND_PER_VERTEX); +#else + geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getTangentArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); +#endif n = _effect->getGenerator(Effect::BINORMAL); if (n != -1 && !geometry->getVertexAttribArray(n)) - geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getBinormalArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); +#if OSG_MIN_VERSION_REQUIRED(3,1,8) + geometry->setVertexAttribArray(n, tsg->getBinormalArray(), osg::Array::BIND_PER_VERTEX); +#else + geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getBinormalArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); +#endif n = _effect->getGenerator(Effect::NORMAL); if (n != -1 && !geometry->getVertexAttribArray(n)) - geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getNormalArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); +#if OSG_MIN_VERSION_REQUIRED(3,1,8) + geometry->setVertexAttribArray(n, tsg->getNormalArray(), osg::Array::BIND_PER_VERTEX); +#else + geometry->setVertexAttribData(n, osg::Geometry::ArrayData(tsg->getNormalArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE)); +#endif } } diff -Nru simgear-2.10.0/simgear/scene/material/Effect.hxx simgear-3.0.0/simgear/scene/material/Effect.hxx --- simgear-2.10.0/simgear/scene/material/Effect.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/Effect.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -176,6 +176,8 @@ bool makeParametersFromStateSet(SGPropertyNode* paramRoot, const osg::StateSet* ss); +void clearEffectCache(); + namespace effect { /** diff -Nru simgear-2.10.0/simgear/scene/material/GLPredicate.cxx simgear-3.0.0/simgear/scene/material/GLPredicate.cxx --- simgear-2.10.0/simgear/scene/material/GLPredicate.cxx 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/GLPredicate.cxx 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -#include - -#include -#include - -#include -#include - -namespace simgear -{ -using namespace std; -using namespace osg; -using namespace boost; - -bool GLPredicate::operator ()(unsigned int contextID) -{ - float versionNumber = getGLVersionNumber() * 10.0f; - float required = (static_cast(majorVersion) * 10.0f - + static_cast(minorVersion)); - if (versionNumber < required - && !osg::equivalent(versionNumber, required)) - return false; - return (find_if(extensions.begin(), extensions.end(), - !bind(isGLExtensionSupported, contextID, - bind(&string::c_str, _1))) - == extensions.end()); -} -} diff -Nru simgear-2.10.0/simgear/scene/material/GLPredicate.hxx simgear-3.0.0/simgear/scene/material/GLPredicate.hxx --- simgear-2.10.0/simgear/scene/material/GLPredicate.hxx 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/GLPredicate.hxx 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -#ifndef SIMGEAR_GLPREDICATE_HXX -#define SIMGEAR_GLPREDICATE_HXX 1 - -#include -#include - -namespace simgear -{ - -struct GLPredicate -{ - GLPredicate() : majorVersion(0),minorVersion(0) {} - GLPredicate(int majorVersion_, int minorVersion_) : - majorVersion(majorVersion_), minorVersion(minorVersion_) - { - } - /** Does OpenGL support the required version and extensions? - */ - bool operator ()(unsigned int contextID); - int majorVersion; - int minorVersion; - std::vector extensions; -}; -} -#endif diff -Nru simgear-2.10.0/simgear/scene/material/makeEffect.cxx simgear-3.0.0/simgear/scene/material/makeEffect.cxx --- simgear-2.10.0/simgear/scene/material/makeEffect.cxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/makeEffect.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -270,4 +270,10 @@ return effect.release(); } +void clearEffectCache() +{ + OpenThreads::ScopedLock lock(effectMutex); + effectMap.clear(); +} + } diff -Nru simgear-2.10.0/simgear/scene/material/mat.cxx simgear-3.0.0/simgear/scene/material/mat.cxx --- simgear-2.10.0/simgear/scene/material/mat.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/mat.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -50,6 +50,8 @@ #include #include #include +#include + #include #include #include @@ -202,7 +204,7 @@ } } - if (textures.size() == 0 && texturesets.size() == 0) { + if (textures.empty() && texturesets.empty()) { SGPath tpath("Textures"); tpath.append("Terrain"); tpath.append("unknown.rgb"); @@ -320,6 +322,8 @@ building_large_max_width = props->getFloatValue("building-large-max-width-m", 75.0); building_large_min_depth = props->getFloatValue("building-large-min-depth-m", 50.0); building_large_max_depth = props->getFloatValue("building-large-max-depth-m", 75.0); + + building_range = props->getDoubleValue("building-range-m", 10000.0); cos_object_max_density_slope_angle = cos(props->getFloatValue("object-max-density-angle-deg", 20.0) * osg::PI/180.0); cos_object_zero_density_slope_angle = cos(props->getFloatValue("object-zero-density-angle-deg", 30.0) * osg::PI/180.0); @@ -453,7 +457,8 @@ Effect* SGMaterial::get_effect(const SGTexturedTriangleBin& triangleBin) { - if (_status.size() == 0) { + SGGuard g(_lock); + if (_status.empty()) { SG_LOG( SG_GENERAL, SG_WARN, "No effect available."); return 0; } @@ -464,13 +469,14 @@ Effect* SGMaterial::get_effect() { + SGGuard g(_lock); return get_effect(0); } osg::Texture2D* SGMaterial::get_object_mask(const SGTexturedTriangleBin& triangleBin) { - if (_status.size() == 0) { + if (_status.empty()) { SG_LOG( SG_GENERAL, SG_WARN, "No mask available."); return 0; } diff -Nru simgear-2.10.0/simgear/scene/material/mat.hxx simgear-3.0.0/simgear/scene/material/mat.hxx --- simgear-2.10.0/simgear/scene/material/mat.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/mat.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -43,6 +43,7 @@ } #include +#include // for SGMutex #include #include @@ -211,6 +212,8 @@ inline double get_building_large_min_depth () const { return building_large_min_depth; } inline double get_building_large_max_depth () const { return building_large_max_depth; } + inline double get_building_range () const { return building_range; } + inline double get_cos_object_max_density_slope_angle () const { return cos_object_max_density_slope_angle; } inline double get_cos_object_zero_density_slope_angle () const { return cos_object_zero_density_slope_angle; } @@ -415,6 +418,8 @@ double building_large_min_depth; double building_large_max_depth; + double building_range; + // Cosine of the angle of maximum and zero density, // used to stop buildings and random objects from being // created on too steep a slope. @@ -469,6 +474,9 @@ // Parameters from the materials file const SGPropertyNode* parameters; + // per-material lock for entrypoints called from multiple threads + SGMutex _lock; + //////////////////////////////////////////////////////////////////// // Internal constructors and methods. //////////////////////////////////////////////////////////////////// diff -Nru simgear-2.10.0/simgear/scene/material/matlib.cxx simgear-3.0.0/simgear/scene/material/matlib.cxx --- simgear-2.10.0/simgear/scene/material/matlib.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/matlib.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include "mat.hxx" @@ -49,8 +51,17 @@ using std::string; + +class SGMaterialLib::MatLibPrivate +{ +public: + SGMutex mutex; +}; + // Constructor -SGMaterialLib::SGMaterialLib ( void ) { +SGMaterialLib::SGMaterialLib ( void ) : + d(new MatLibPrivate) +{ } // Load a library of material properties @@ -96,15 +107,16 @@ } // find a material record by material name -SGMaterial *SGMaterialLib::find( const string& material ) { +SGMaterial *SGMaterialLib::find( const string& material ) const +{ SGMaterial *result = NULL; - material_map_iterator it = matlib.find( material ); + const_material_map_iterator it = matlib.find( material ); if ( it != end() ) { // We now have a list of materials that match this // name. Find the first one that either doesn't have // a condition, or has a condition that evaluates // to true. - material_list_iterator iter = it->second.begin(); + material_list::const_iterator iter = it->second.begin(); while (iter != it->second.end()) { result = *iter; if (result->valid()) { @@ -117,6 +129,31 @@ return NULL; } +void SGMaterialLib::refreshActiveMaterials() +{ + active_material_cache newCache; + material_map_iterator it = matlib.begin(); + for (; it != matlib.end(); ++it) { + newCache[it->first] = find(it->first); + } + + // use this approach to minimise the time we're holding the lock + // lock on the mutex (and hence, would block findCached calls) + SGGuard g(d->mutex); + active_cache = newCache; +} + +SGMaterial *SGMaterialLib::findCached( const string& material ) const +{ + SGGuard g(d->mutex); + + active_material_cache::const_iterator it = active_cache.find(material); + if (it == active_cache.end()) + return NULL; + + return it->second; +} + // Destructor SGMaterialLib::~SGMaterialLib ( void ) { SG_LOG( SG_GENERAL, SG_INFO, "SGMaterialLib::~SGMaterialLib() size=" << matlib.size()); diff -Nru simgear-2.10.0/simgear/scene/material/matlib.hxx simgear-3.0.0/simgear/scene/material/matlib.hxx --- simgear-2.10.0/simgear/scene/material/matlib.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/matlib.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -27,8 +27,10 @@ #include +#include #include +#include #include // Standard C++ string library #include // STL associative "array" #include // STL "array" @@ -40,19 +42,26 @@ namespace osg { class Geode; } // Material management class -class SGMaterialLib { +class SGMaterialLib : public SGReferenced +{ private: - + class MatLibPrivate; + std::auto_ptr d; + // associative array of materials typedef std::vector< SGSharedPtr > material_list; typedef material_list::iterator material_list_iterator; + typedef std::map < std::string, material_list> material_map; typedef material_map::iterator material_map_iterator; typedef material_map::const_iterator const_material_map_iterator; material_map matlib; - + + typedef std::map < std::string, SGSharedPtr > active_material_cache; + active_material_cache active_cache; + public: // Constructor @@ -62,8 +71,24 @@ bool load( const std::string &fg_root, const std::string& mpath, SGPropertyNode *prop_root ); // find a material record by material name - SGMaterial *find( const std::string& material ); + SGMaterial *find( const std::string& material ) const; + /** + * Material lookup involves evaluation of SGConditions to determine which + * possible material (by season, region, etc) is valid. This involves + * vproperty tree queries, so repeated calls to find() can cause + * race conditions when called from the osgDB pager thread. (especially + * during startup) + * + * To fix this, and also avoid repeated re-evaluation of the material + * conditions, we provide a version which uses a cached, threadsafe table + * of the currently valid materials. The main thread calls the refresh + * method below to evaluate the valid materials, and findCached can be + * safely called from other threads with no access to unprotected state. + */ + SGMaterial *findCached( const std::string& material ) const; + void refreshActiveMaterials(); + material_map_iterator begin() { return matlib.begin(); } const_material_map_iterator begin() const { return matlib.begin(); } @@ -76,5 +101,6 @@ ~SGMaterialLib ( void ); }; +typedef SGSharedPtr SGMaterialLibPtr; #endif // _MATLIB_HXX diff -Nru simgear-2.10.0/simgear/scene/material/parseBlendFunc.cxx simgear-3.0.0/simgear/scene/material/parseBlendFunc.cxx --- simgear-2.10.0/simgear/scene/material/parseBlendFunc.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/parseBlendFunc.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,98 @@ +// Parse osg::BlendFunc from property nodes +// +// Copyright (C) 2008 - 2010 Tim Moore timoore33@gmail.com +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "parseBlendFunc.hxx" +#include "EffectBuilder.hxx" +#include +#include + +using osg::BlendFunc; + +namespace simgear +{ + + //---------------------------------------------------------------------------- + extern effect::EffectPropertyMap blendFuncModes; + + //---------------------------------------------------------------------------- + bool parseBlendFunc( osg::StateSet* ss, + const SGPropertyNode* src, + const SGPropertyNode* dest, + const SGPropertyNode* src_rgb, + const SGPropertyNode* dest_rgb, + const SGPropertyNode* src_alpha, + const SGPropertyNode* dest_alpha ) + { + if( !ss ) + return false; + + BlendFunc::BlendFuncMode src_mode = BlendFunc::ONE; + BlendFunc::BlendFuncMode dest_mode = BlendFunc::ZERO; + + if( src ) + findAttr(blendFuncModes, src, src_mode); + if( dest ) + findAttr(blendFuncModes, dest, dest_mode); + + if( src && dest + && !(src_rgb || src_alpha || dest_rgb || dest_alpha) + && src_mode == BlendFunc::SRC_ALPHA + && dest_mode == BlendFunc::ONE_MINUS_SRC_ALPHA ) + { + ss->setAttributeAndModes( + StateAttributeFactory::instance()->getStandardBlendFunc() + ); + return true; + } + + BlendFunc* blend_func = new BlendFunc; + if( src ) + blend_func->setSource(src_mode); + if( dest ) + blend_func->setDestination(dest_mode); + + if( src_rgb ) + { + BlendFunc::BlendFuncMode sourceRGBMode; + findAttr(blendFuncModes, src_rgb, sourceRGBMode); + blend_func->setSourceRGB(sourceRGBMode); + } + if( dest_rgb) + { + BlendFunc::BlendFuncMode destRGBMode; + findAttr(blendFuncModes, dest_rgb, destRGBMode); + blend_func->setDestinationRGB(destRGBMode); + } + if( src_alpha ) + { + BlendFunc::BlendFuncMode sourceAlphaMode; + findAttr(blendFuncModes, src_alpha, sourceAlphaMode); + blend_func->setSourceAlpha(sourceAlphaMode); + } + if( dest_alpha) + { + BlendFunc::BlendFuncMode destAlphaMode; + findAttr(blendFuncModes, dest_alpha, destAlphaMode); + blend_func->setDestinationAlpha(destAlphaMode); + } + ss->setAttributeAndModes(blend_func); + return true; + } + +} // namespace simgear diff -Nru simgear-2.10.0/simgear/scene/material/parseBlendFunc.hxx simgear-3.0.0/simgear/scene/material/parseBlendFunc.hxx --- simgear-2.10.0/simgear/scene/material/parseBlendFunc.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/parseBlendFunc.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,52 @@ +///@file +/// Parse osg::BlendFunc from property nodes +/// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_PARSE_BLEND_FUNC_HXX_ +#define SG_PARSE_BLEND_FUNC_HXX_ + +#include +#include + +namespace simgear +{ + + /** + * Parse a blend function from the given property nodes and apply it to the + * given osg::StateSet. + * + * @param ss StateState which the blend function will be applied to + * @param src + * @param dest + * @param src_rgb + * @param dest_rgb + * @param src_alpha + * @param dest_alpha + */ + bool parseBlendFunc( osg::StateSet* ss, + const SGPropertyNode* src = 0, + const SGPropertyNode* dest = 0, + const SGPropertyNode* src_rgb = 0, + const SGPropertyNode* dest_rgb = 0, + const SGPropertyNode* src_alpha = 0, + const SGPropertyNode* dest_alpha = 0 ); + +} // namespace simgear + + +#endif /* SG_PARSE_BLEND_FUNC_HXX_ */ diff -Nru simgear-2.10.0/simgear/scene/material/parseBlendFunc_test.cxx simgear-3.0.0/simgear/scene/material/parseBlendFunc_test.cxx --- simgear-2.10.0/simgear/scene/material/parseBlendFunc_test.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/parseBlendFunc_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,63 @@ +#include + +#include "parseBlendFunc.hxx" +#include +#include + +#include + +#define COMPARE(a, b) \ + if( (a) != (b) ) \ + { \ + std::cerr << "line " << __LINE__ << ": failed: "\ + << #a << " != " << #b << std::endl; \ + return 1; \ + } + +#define VERIFY(a) \ + if( !(a) ) \ + { \ + std::cerr << "line " << __LINE__ << ": failed: "\ + << #a << std::endl; \ + return 1; \ + } + +int main (int ac, char ** av) +{ + osg::ref_ptr ss = new osg::StateSet; + + // default blendfunc + VERIFY( simgear::parseBlendFunc(ss) ); + + osg::BlendFunc* bf = dynamic_cast( + ss->getAttribute(osg::StateAttribute::BLENDFUNC) + ); + + VERIFY( bf ); + COMPARE(bf->getSource(), osg::BlendFunc::SRC_ALPHA); + COMPARE(bf->getDestination(), osg::BlendFunc::ONE_MINUS_SRC_ALPHA); + COMPARE(bf->getSource(), bf->getSourceAlpha()); + COMPARE(bf->getDestination(), bf->getDestinationAlpha()); + + // now set some values + SGPropertyNode_ptr src = new SGPropertyNode, + dest = new SGPropertyNode; + + src->setStringValue("src-alpha"); + dest->setStringValue("constant-color"); + + VERIFY( simgear::parseBlendFunc(ss, src, dest) ); + + bf = dynamic_cast( + ss->getAttribute(osg::StateAttribute::BLENDFUNC) + ); + + VERIFY( bf ); + COMPARE(bf->getSource(), osg::BlendFunc::SRC_ALPHA); + COMPARE(bf->getDestination(), osg::BlendFunc::CONSTANT_COLOR); + COMPARE(bf->getSource(), bf->getSourceAlpha()); + COMPARE(bf->getDestination(), bf->getDestinationAlpha()); + + std::cout << "all tests passed successfully!" << std::endl; + return 0; +} diff -Nru simgear-2.10.0/simgear/scene/material/Technique.cxx simgear-3.0.0/simgear/scene/material/Technique.cxx --- simgear-2.10.0/simgear/scene/material/Technique.cxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/Technique.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -118,7 +118,7 @@ Status oldVal = contextInfo.valid(); Status newVal = INVALID; expression::FixedLengthBinding<1> binding; - binding.getBindings()[_contextIdLocation].val.intVal = contextId; + binding.getBindings()[_contextIdLocation] = expression::Value((int) contextId); if (_validExpression->getValue(&binding)) newVal = VALID; contextInfo.valid.compareAndSwap(oldVal, newVal); @@ -167,12 +167,12 @@ BOOST_FOREACH(ref_ptr& pass, passes) { osg::ref_ptr ss = pass; - if (ecv && ( pass->getBufferUnitList().size() != 0 || pass->getPositionedUniformMap().size() != 0 ) ) { + if (ecv && ( ! pass->getBufferUnitList().empty() || ! pass->getPositionedUniformMap().empty() ) ) { ss = static_cast( - pass->clone( osg::CopyOp( ( pass->getBufferUnitList().size() != 0 ? + pass->clone( osg::CopyOp( ( ! pass->getBufferUnitList().empty() ? osg::CopyOp::DEEP_COPY_TEXTURES : osg::CopyOp::SHALLOW_COPY ) | - ( pass->getPositionedUniformMap().size() != 0 ? + ( ! pass->getPositionedUniformMap().empty() ? osg::CopyOp::DEEP_COPY_UNIFORMS : osg::CopyOp::SHALLOW_COPY ) ) ) @@ -271,19 +271,19 @@ { public: ExtensionSupportedExpression() {} - ExtensionSupportedExpression(const string& extString) + ExtensionSupportedExpression(const std::string& extString) : _extString(extString) { } - const string& getExtensionString() { return _extString; } - void setExtensionString(const string& extString) { _extString = extString; } + const std::string& getExtensionString() { return _extString; } + void setExtensionString(const std::string& extString) { _extString = extString; } void eval(bool&value, const expression::Binding* b) const { int contextId = getOperand(0)->getValue(b); value = isGLExtensionSupported((unsigned)contextId, _extString.c_str()); } protected: - string _extString; + std::string _extString; }; Expression* extensionSupportedParser(const SGPropertyNode* exp, diff -Nru simgear-2.10.0/simgear/scene/material/TextureBuilder.cxx simgear-3.0.0/simgear/scene/material/TextureBuilder.cxx --- simgear-2.10.0/simgear/scene/material/TextureBuilder.cxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/scene/material/TextureBuilder.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -233,44 +233,47 @@ texType, mipmapFunctions); } -void setAttrs(const TexTuple& attrs, Texture* tex, +bool setAttrs(const TexTuple& attrs, Texture* tex, const SGReaderWriterOptions* options) { const string& imageName = attrs.get<0>(); - if (imageName.empty()) { - throw BuilderException("no image file"); - } else { - osgDB::ReaderWriter::ReadResult result; - result = osgDB::readImageFile(imageName, options); - osg::ref_ptr image; - if (result.success()) - image = result.getImage(); - if (image.valid()) - { - image = computeMipmap( image.get(), attrs.get<7>() ); - tex->setImage(GL_FRONT_AND_BACK, image.get()); - int s = image->s(); - int t = image->t(); - if (s <= t && 32 <= s) { - SGSceneFeatures::instance()->setTextureCompression(tex); - } else if (t < s && 32 <= t) { - SGSceneFeatures::instance()->setTextureCompression(tex); - } - tex->setMaxAnisotropy(SGSceneFeatures::instance() - ->getTextureFilter()); - } else { - SG_LOG(SG_INPUT, SG_ALERT, "failed to load effect texture file " - << imageName); + if (imageName.empty()) + return false; + + osgDB::ReaderWriter::ReadResult result; + result = osgDB::readImageFile(imageName, options); + osg::ref_ptr image; + if (result.success()) + image = result.getImage(); + if (image.valid()) + { + image = computeMipmap( image.get(), attrs.get<7>() ); + tex->setImage(GL_FRONT_AND_BACK, image.get()); + int s = image->s(); + int t = image->t(); + if (s <= t && 32 <= s) { + SGSceneFeatures::instance()->setTextureCompression(tex); + } else if (t < s && 32 <= t) { + SGSceneFeatures::instance()->setTextureCompression(tex); } + tex->setMaxAnisotropy(SGSceneFeatures::instance() + ->getTextureFilter()); + } else { + SG_LOG(SG_INPUT, SG_ALERT, "failed to load effect texture file " + << imageName); + return false; } + // texture->setDataVariance(osg::Object::STATIC); tex->setFilter(Texture::MIN_FILTER, attrs.get<1>()); tex->setFilter(Texture::MAG_FILTER, attrs.get<2>()); tex->setWrap(Texture::WRAP_S, attrs.get<3>()); tex->setWrap(Texture::WRAP_T, attrs.get<4>()); tex->setWrap(Texture::WRAP_R, attrs.get<5>()); + return true; } -} + +} // of anonymous namespace template class TexBuilder : public TextureBuilder @@ -300,7 +303,9 @@ } tex = new T; - setAttrs(attrs, tex, options); + if (!setAttrs(attrs, tex, options)) + return NULL; + if (itr == texMap.end()) texMap.insert(make_pair(attrs, tex)); else diff -Nru simgear-2.10.0/simgear/scene/model/animation.cxx simgear-3.0.0/simgear/scene/model/animation.cxx --- simgear-2.10.0/simgear/scene/model/animation.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/animation.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -24,8 +24,6 @@ #include #include #include -#include -#include #include #include #include @@ -41,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -59,6 +56,8 @@ #include "SGRotateTransform.hxx" #include "SGScaleTransform.hxx" #include "SGInteractionAnimation.hxx" +#include "SGPickAnimation.hxx" +#include "SGTrackToAnimation.hxx" #include "ConditionNode.hxx" @@ -67,7 +66,6 @@ using OpenThreads::ScopedLock; using namespace simgear; - //////////////////////////////////////////////////////////////////////// // Static utility functions. //////////////////////////////////////////////////////////////////////// @@ -208,7 +206,6 @@ return 0; } - //////////////////////////////////////////////////////////////////////// // Animation installer //////////////////////////////////////////////////////////////////////// @@ -347,7 +344,7 @@ if (!_found) { std::list::const_iterator i; - string info; + std::string info; for (i = _objectNames.begin(); i != _objectNames.end(); ++i) { if (!info.empty()) @@ -368,7 +365,7 @@ SGAnimation::animate(osg::Node* node, const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const osgDB::Options* options, - const string &path, int i) + const std::string &path, int i) { std::string type = configNode->getStringValue("type", "none"); if (type == "alpha-test") { @@ -398,6 +395,12 @@ } else if (type == "pick") { SGPickAnimation animInst(configNode, modelRoot); animInst.apply(node); + } else if (type == "knob") { + SGKnobAnimation animInst(configNode, modelRoot); + animInst.apply(node); + } else if (type == "slider") { + SGSliderAnimation animInst(configNode, modelRoot); + animInst.apply(node); } else if (type == "range") { SGRangeAnimation animInst(configNode, modelRoot); animInst.apply(node); @@ -420,6 +423,9 @@ } else if (type == "timed") { SGTimedAnimation animInst(configNode, modelRoot); animInst.apply(node); + } else if (type == "locked-track") { + SGTrackToAnimation animInst(node, configNode, modelRoot); + animInst.apply(node); } else if (type == "translate") { SGTranslateAnimation animInst(configNode, modelRoot); animInst.apply(node); @@ -526,6 +532,65 @@ } } +//------------------------------------------------------------------------------ +SGVec3d SGAnimation::readVec3( const std::string& name, + const std::string& suffix, + const SGVec3d& def ) const +{ + SGVec3d vec; + vec[0] = _configNode->getDoubleValue(name + "/x" + suffix, def.x()); + vec[1] = _configNode->getDoubleValue(name + "/y" + suffix, def.y()); + vec[2] = _configNode->getDoubleValue(name + "/z" + suffix, def.z()); + return vec; +} + +//------------------------------------------------------------------------------ +// factored out to share with SGKnobAnimation +void SGAnimation::readRotationCenterAndAxis( SGVec3d& center, + SGVec3d& axis ) const +{ + center = SGVec3d::zeros(); + if( _configNode->hasValue("axis/x1-m") ) + { + SGVec3d v1 = readVec3("axis", "1-m"), // axis/[xyz]1-m + v2 = readVec3("axis", "2-m"); // axis/[xyz]2-m + center = 0.5*(v1+v2); + axis = v2 - v1; + } + else + { + axis = readVec3("axis"); + } + if( 8 * SGLimitsd::min() < norm(axis) ) + axis = normalize(axis); + + center = readVec3("center", "-m", center); +} + +//------------------------------------------------------------------------------ +SGExpressiond* SGAnimation::readOffsetValue(const char* tag_name) const +{ + const SGPropertyNode* node = _configNode->getChild(tag_name); + if( !node ) + return 0; + + SGExpressiond_ref expression; + if( !node->nChildren() ) + expression = new SGConstExpression(node->getDoubleValue()); + else + expression = SGReadDoubleExpression(_modelRoot, node->getChild(0)); + + if( !expression ) + return 0; + + expression = expression->simplify(); + + if( expression->isConst() && expression->getValue() == 0 ) + return 0; + + return expression.release(); +} + void SGAnimation::removeMode(osg::Node& node, osg::StateAttribute::GLMode mode) { @@ -580,7 +645,7 @@ } - + //////////////////////////////////////////////////////////////////////// // Implementation of null animation //////////////////////////////////////////////////////////////////////// @@ -602,7 +667,7 @@ return group; } - + //////////////////////////////////////////////////////////////////////// // Implementation of translate animation //////////////////////////////////////////////////////////////////////// @@ -644,22 +709,7 @@ else _initialValue = 0; - if (configNode->hasValue("axis/x1-m")) { - SGVec3d v1, v2; - v1[0] = configNode->getDoubleValue("axis/x1-m", 0); - v1[1] = configNode->getDoubleValue("axis/y1-m", 0); - v1[2] = configNode->getDoubleValue("axis/z1-m", 0); - v2[0] = configNode->getDoubleValue("axis/x2-m", 0); - v2[1] = configNode->getDoubleValue("axis/y2-m", 0); - v2[2] = configNode->getDoubleValue("axis/z2-m", 0); - _axis = v2 - v1; - } else { - _axis[0] = configNode->getDoubleValue("axis/x", 0); - _axis[1] = configNode->getDoubleValue("axis/y", 0); - _axis[2] = configNode->getDoubleValue("axis/z", 0); - } - if (8*SGLimitsd::min() < norm(_axis)) - _axis = normalize(_axis); + _axis = readTranslateAxis(configNode); } osg::Group* @@ -677,7 +727,7 @@ return transform; } - + //////////////////////////////////////////////////////////////////////// // Implementation of rotate/spin animation //////////////////////////////////////////////////////////////////////// @@ -800,7 +850,7 @@ if (!cv) return; if (!_condition || _condition->test()) { - double t = nv->getFrameStamp()->getReferenceTime(); + double t = nv->getFrameStamp()->getSimulationTime(); double rps = _animationValue->getValue() / 60.0; ref_ptr refval(static_cast(_referenceValues.get())); @@ -848,6 +898,30 @@ } } +SGVec3d readTranslateAxis(const SGPropertyNode* configNode) +{ + SGVec3d axis; + + if (configNode->hasValue("axis/x1-m")) { + SGVec3d v1, v2; + v1[0] = configNode->getDoubleValue("axis/x1-m", 0); + v1[1] = configNode->getDoubleValue("axis/y1-m", 0); + v1[2] = configNode->getDoubleValue("axis/z1-m", 0); + v2[0] = configNode->getDoubleValue("axis/x2-m", 0); + v2[1] = configNode->getDoubleValue("axis/y2-m", 0); + v2[2] = configNode->getDoubleValue("axis/z2-m", 0); + axis = v2 - v1; + } else { + axis[0] = configNode->getDoubleValue("axis/x", 0); + axis[1] = configNode->getDoubleValue("axis/y", 0); + axis[2] = configNode->getDoubleValue("axis/z", 0); + } + if (8*SGLimitsd::min() < norm(axis)) + axis = normalize(axis); + + return axis; +} + SGRotateAnimation::SGRotateAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) : SGAnimation(configNode, modelRoot) @@ -864,28 +938,8 @@ _initialValue = _animationValue->getValue(); else _initialValue = 0; - _center = SGVec3d::zeros(); - if (configNode->hasValue("axis/x1-m")) { - SGVec3d v1, v2; - v1[0] = configNode->getDoubleValue("axis/x1-m", 0); - v1[1] = configNode->getDoubleValue("axis/y1-m", 0); - v1[2] = configNode->getDoubleValue("axis/z1-m", 0); - v2[0] = configNode->getDoubleValue("axis/x2-m", 0); - v2[1] = configNode->getDoubleValue("axis/y2-m", 0); - v2[2] = configNode->getDoubleValue("axis/z2-m", 0); - _center = 0.5*(v1+v2); - _axis = v2 - v1; - } else { - _axis[0] = configNode->getDoubleValue("axis/x", 0); - _axis[1] = configNode->getDoubleValue("axis/y", 0); - _axis[2] = configNode->getDoubleValue("axis/z", 0); - } - if (8*SGLimitsd::min() < norm(_axis)) - _axis = normalize(_axis); - - _center[0] = configNode->getDoubleValue("center/x-m", _center[0]); - _center[1] = configNode->getDoubleValue("center/y-m", _center[1]); - _center[2] = configNode->getDoubleValue("center/z-m", _center[2]); + + readRotationCenterAndAxis(_center, _axis); } osg::Group* @@ -915,7 +969,7 @@ } } - + //////////////////////////////////////////////////////////////////////// // Implementation of scale animation //////////////////////////////////////////////////////////////////////// @@ -1049,7 +1103,7 @@ return transform; } - + // Don't create a new state state everytime we need GL_NORMALIZE! namespace @@ -1195,7 +1249,7 @@ &SGDistScaleAnimation::Transform::writeLocalData ); } - + //////////////////////////////////////////////////////////////////////// // Implementation of flash animation //////////////////////////////////////////////////////////////////////// @@ -1351,7 +1405,7 @@ &SGFlashAnimation::Transform::writeLocalData ); } - + //////////////////////////////////////////////////////////////////////// // Implementation of billboard animation //////////////////////////////////////////////////////////////////////// @@ -1436,7 +1490,7 @@ &SGBillboardAnimation::Transform::writeLocalData ); } - + //////////////////////////////////////////////////////////////////////// // Implementation of a range animation //////////////////////////////////////////////////////////////////////// @@ -1541,7 +1595,7 @@ return group; } - + //////////////////////////////////////////////////////////////////////// // Implementation of a select animation //////////////////////////////////////////////////////////////////////// @@ -1571,7 +1625,7 @@ } - + //////////////////////////////////////////////////////////////////////// // Implementation of alpha test animation //////////////////////////////////////////////////////////////////////// @@ -1641,7 +1695,7 @@ } } - + ////////////////////////////////////////////////////////////////////// // Blend animation installer ////////////////////////////////////////////////////////////////////// @@ -1760,7 +1814,7 @@ node.accept(visitor); } - + ////////////////////////////////////////////////////////////////////// // Timed animation installer ////////////////////////////////////////////////////////////////////// @@ -1808,7 +1862,7 @@ _current_index = _current_index % nChildren; // update the time and compute the current systems time value - double t = nv->getFrameStamp()->getReferenceTime(); + double t = nv->getFrameStamp()->getSimulationTime(); if (_last_time_sec == SGLimitsd::max()) { _last_time_sec = t; } else { @@ -1871,7 +1925,7 @@ return sw; } - + //////////////////////////////////////////////////////////////////////// // dynamically switch on/off shadows //////////////////////////////////////////////////////////////////////// @@ -1917,7 +1971,7 @@ return group; } - + //////////////////////////////////////////////////////////////////////// // Implementation of SGTexTransformAnimation //////////////////////////////////////////////////////////////////////// @@ -2155,305 +2209,3 @@ updateCallback->appendTransform(rotation, value); } - -//////////////////////////////////////////////////////////////////////// -// Implementation of SGPickAnimation -//////////////////////////////////////////////////////////////////////// - -class SGPickAnimation::PickCallback : public SGPickCallback { -public: - PickCallback(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - _repeatable(configNode->getBoolValue("repeatable", false)), - _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)) - { - SG_LOG(SG_INPUT, SG_DEBUG, "Reading all bindings"); - std::vector bindings; - - bindings = configNode->getChildren("button"); - for (unsigned int i = 0; i < bindings.size(); ++i) { - _buttons.push_back( bindings[i]->getIntValue() ); - } - bindings = configNode->getChildren("binding"); - for (unsigned int i = 0; i < bindings.size(); ++i) { - _bindingsDown.push_back(new SGBinding(bindings[i], modelRoot)); - } - - const SGPropertyNode* upNode = configNode->getChild("mod-up"); - if (!upNode) - return; - bindings = upNode->getChildren("binding"); - for (unsigned int i = 0; i < bindings.size(); ++i) { - _bindingsUp.push_back(new SGBinding(bindings[i], modelRoot)); - } - } - virtual bool buttonPressed(int button, const Info&) - { - bool found = false; - for( std::vector::iterator it = _buttons.begin(); it != _buttons.end(); ++it ) { - if( *it == button ) { - found = true; - break; - } - } - if (!found ) - return false; - SGBindingList::const_iterator i; - for (i = _bindingsDown.begin(); i != _bindingsDown.end(); ++i) - (*i)->fire(); - _repeatTime = -_repeatInterval; // anti-bobble: delay start of repeat - return true; - } - virtual void buttonReleased(void) - { - SGBindingList::const_iterator i; - for (i = _bindingsUp.begin(); i != _bindingsUp.end(); ++i) - (*i)->fire(); - } - virtual void update(double dt) - { - if (!_repeatable) - return; - - _repeatTime += dt; - while (_repeatInterval < _repeatTime) { - _repeatTime -= _repeatInterval; - SGBindingList::const_iterator i; - for (i = _bindingsDown.begin(); i != _bindingsDown.end(); ++i) - (*i)->fire(); - } - } -private: - SGBindingList _bindingsDown; - SGBindingList _bindingsUp; - std::vector _buttons; - bool _repeatable; - double _repeatInterval; - double _repeatTime; -}; - -class VncVisitor : public osg::NodeVisitor { - public: - VncVisitor(double x, double y, int mask) : - osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), - _texX(x), _texY(y), _mask(mask), _done(false) - { - SG_LOG(SG_INPUT, SG_DEBUG, "VncVisitor constructor " - << x << "," << y << " mask " << mask); - } - - virtual void apply(osg::Node &node) - { - // Some nodes have state sets attached - touchStateSet(node.getStateSet()); - if (!_done) - traverse(node); - if (_done) return; - // See whether we are a geode worth exploring - osg::Geode *g = dynamic_cast(&node); - if (!g) return; - // Go find all its drawables - int i = g->getNumDrawables(); - while (--i >= 0) { - osg::Drawable *d = g->getDrawable(i); - if (d) touchDrawable(*d); - } - // Out of optimism, do the same for EffectGeode - simgear::EffectGeode *eg = dynamic_cast(&node); - if (!eg) return; - for (simgear::EffectGeode::DrawablesIterator di = eg->drawablesBegin(); - di != eg->drawablesEnd(); di++) { - touchDrawable(**di); - } - // Now see whether the EffectGeode has an Effect - simgear::Effect *e = eg->getEffect(); - if (e) { - touchStateSet(e->getDefaultStateSet()); - } - } - - inline void touchDrawable(osg::Drawable &d) - { - osg::StateSet *ss = d.getStateSet(); - touchStateSet(ss); - } - - void touchStateSet(osg::StateSet *ss) - { - if (!ss) return; - osg::StateAttribute *sa = ss->getTextureAttribute(0, - osg::StateAttribute::TEXTURE); - if (!sa) return; - osg::Texture *t = sa->asTexture(); - if (!t) return; - osg::Image *img = t->getImage(0); - if (!img) return; - if (!_done) { - int pixX = _texX * img->s(); - int pixY = _texY * img->t(); - _done = img->sendPointerEvent(pixX, pixY, _mask); - SG_LOG(SG_INPUT, SG_DEBUG, "VncVisitor image said " << _done - << " to coord " << pixX << "," << pixY); - } - } - - inline bool wasSuccessful() - { - return _done; - } - - private: - double _texX, _texY; - int _mask; - bool _done; -}; - - -class SGPickAnimation::VncCallback : public SGPickCallback { -public: - VncCallback(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot, - osg::Group *node) - : _node(node) - { - SG_LOG(SG_INPUT, SG_DEBUG, "Configuring VNC callback"); - const char *cornernames[3] = {"top-left", "top-right", "bottom-left"}; - SGVec3d *cornercoords[3] = {&_topLeft, &_toRight, &_toDown}; - for (int c =0; c < 3; c++) { - const SGPropertyNode* cornerNode = configNode->getChild(cornernames[c]); - *cornercoords[c] = SGVec3d( - cornerNode->getDoubleValue("x"), - cornerNode->getDoubleValue("y"), - cornerNode->getDoubleValue("z")); - } - _toRight -= _topLeft; - _toDown -= _topLeft; - _squaredRight = dot(_toRight, _toRight); - _squaredDown = dot(_toDown, _toDown); - } - - virtual bool buttonPressed(int button, const Info& info) - { - SGVec3d loc(info.local); - SG_LOG(SG_INPUT, SG_DEBUG, "VNC pressed " << button << ": " << loc); - loc -= _topLeft; - _x = dot(loc, _toRight) / _squaredRight; - _y = dot(loc, _toDown) / _squaredDown; - if (_x<0) _x = 0; else if (_x > 1) _x = 1; - if (_y<0) _y = 0; else if (_y > 1) _y = 1; - VncVisitor vv(_x, _y, 1 << button); - _node->accept(vv); - return vv.wasSuccessful(); - - } - virtual void buttonReleased(void) - { - SG_LOG(SG_INPUT, SG_DEBUG, "VNC release"); - VncVisitor vv(_x, _y, 0); - _node->accept(vv); - } - virtual void update(double dt) - { - } -private: - double _x, _y; - osg::ref_ptr _node; - SGVec3d _topLeft, _toRight, _toDown; - double _squaredRight, _squaredDown; -}; - -SGPickAnimation::SGPickAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot) : - SGAnimation(configNode, modelRoot) -{ -} - -namespace -{ -Mutex colorModeUniformMutex; -osg::ref_ptr colorModeUniform; -} - -osg::Group* -SGPickAnimation::createAnimationGroup(osg::Group& parent) -{ - osg::Group* commonGroup = new osg::Group; - - // Contains the normal geometry that is interactive - osg::ref_ptr normalGroup = new osg::Group; - normalGroup->setName("pick normal group"); - normalGroup->addChild(commonGroup); - - // Used to render the geometry with just yellow edges - osg::Group* highlightGroup = new osg::Group; - highlightGroup->setName("pick highlight group"); - highlightGroup->setNodeMask(SG_NODEMASK_PICK_BIT); - highlightGroup->addChild(commonGroup); - SGSceneUserData* ud; - ud = SGSceneUserData::getOrCreateSceneUserData(commonGroup); - - // add actions that become macro and command invocations - std::vector actions; - actions = getConfig()->getChildren("action"); - for (unsigned int i = 0; i < actions.size(); ++i) - ud->addPickCallback(new PickCallback(actions[i], getModelRoot())); - // Look for the VNC sessions that want raw mouse input - actions = getConfig()->getChildren("vncaction"); - for (unsigned int i = 0; i < actions.size(); ++i) - ud->addPickCallback(new VncCallback(actions[i], getModelRoot(), - &parent)); - - // prepare a state set that paints the edges of this object yellow - // The material and texture attributes are set with - // OVERRIDE|PROTECTED in case there is a material animation on a - // higher node in the scene graph, which would have its material - // attribute set with OVERRIDE. - osg::StateSet* stateSet = highlightGroup->getOrCreateStateSet(); - osg::Texture2D* white = StateAttributeFactory::instance()->getWhiteTexture(); - stateSet->setTextureAttributeAndModes(0, white, - (osg::StateAttribute::ON - | osg::StateAttribute::OVERRIDE - | osg::StateAttribute::PROTECTED)); - osg::PolygonOffset* polygonOffset = new osg::PolygonOffset; - polygonOffset->setFactor(-1); - polygonOffset->setUnits(-1); - stateSet->setAttribute(polygonOffset, osg::StateAttribute::OVERRIDE); - stateSet->setMode(GL_POLYGON_OFFSET_LINE, - osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); - osg::PolygonMode* polygonMode = new osg::PolygonMode; - polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK, - osg::PolygonMode::LINE); - stateSet->setAttribute(polygonMode, osg::StateAttribute::OVERRIDE); - osg::Material* material = new osg::Material; - material->setColorMode(osg::Material::OFF); - material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 1)); - // XXX Alpha < 1.0 in the diffuse material value is a signal to the - // default shader to take the alpha value from the material value - // and not the glColor. In many cases the pick animation geometry is - // transparent, so the outline would not be visible without this hack. - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, .95)); - material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1, 1, 0, 1)); - material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 0)); - stateSet->setAttribute( - material, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); - // The default shader has a colorMode uniform that mimics the - // behavior of Material color mode. - osg::Uniform* cmUniform = 0; - { - ScopedLock lock(colorModeUniformMutex); - if (!colorModeUniform.valid()) { - colorModeUniform = new osg::Uniform(osg::Uniform::INT, "colorMode"); - colorModeUniform->set(0); // MODE_OFF - colorModeUniform->setDataVariance(osg::Object::STATIC); - } - cmUniform = colorModeUniform.get(); - } - stateSet->addUniform(cmUniform, - osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); - // Only add normal geometry if configured - if (getConfig()->getBoolValue("visible", true)) - parent.addChild(normalGroup.get()); - parent.addChild(highlightGroup); - - return commonGroup; -} diff -Nru simgear-2.10.0/simgear/scene/model/animation.hxx simgear-3.0.0/simgear/scene/model/animation.hxx --- simgear-2.10.0/simgear/scene/model/animation.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/animation.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -34,11 +34,12 @@ SGExpressiond* read_value(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const char* unit, double defMin, double defMax); - -////////////////////////////////////////////////////////////////////// -// Base class for animation installers -////////////////////////////////////////////////////////////////////// +SGVec3d readTranslateAxis(const SGPropertyNode* configNode); + +/** + * Base class for animation installers + */ class SGAnimation : protected osg::NodeVisitor { public: SGAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot); @@ -47,7 +48,7 @@ static bool animate(osg::Node* node, const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const osgDB::Options* options, - const string &path, int i); + const std::string &path, int i); protected: void apply(osg::Node* node); @@ -57,6 +58,23 @@ virtual void apply(osg::Group& group); + /** + * Read a 3d vector from the configuration property node. + * + * Reads values from @a name/[xyz]@a prefix and defaults to the according + * value of @a def for each value which is not set. + * + * @param name Name of the root node containing all coordinates + * @param suffix Suffix appended to each child node (x,y,z) + * @param def Vector containing default values + */ + SGVec3d readVec3( const std::string& name, + const std::string& suffix = "", + const SGVec3d& def = SGVec3d::zeros() ) const; + void readRotationCenterAndAxis(SGVec3d& center, SGVec3d& axis) const; + + SGExpressiond* readOffsetValue(const char* tag_name) const; + void removeMode(osg::Node& node, osg::StateAttribute::GLMode mode); void removeAttribute(osg::Node& node, osg::StateAttribute::Type type); void removeTextureMode(osg::Node& node, unsigned unit, @@ -76,6 +94,7 @@ const SGCondition* getCondition() const; + std::list _objectNames; private: void installInGroup(const std::string& name, osg::Group& group, osg::ref_ptr& animationGroup); @@ -91,12 +110,12 @@ std::string _name; SGSharedPtr _configNode; SGPropertyNode* _modelRoot; - std::list _objectNames; + std::list > _installedAnimations; bool _enableHOT; }; - + ////////////////////////////////////////////////////////////////////// // Null animation installer ////////////////////////////////////////////////////////////////////// @@ -107,7 +126,7 @@ virtual osg::Group* createAnimationGroup(osg::Group& parent); }; - + ////////////////////////////////////////////////////////////////////// // Translate animation installer ////////////////////////////////////////////////////////////////////// @@ -125,7 +144,7 @@ double _initialValue; }; - + ////////////////////////////////////////////////////////////////////// // Rotate/Spin animation installer ////////////////////////////////////////////////////////////////////// @@ -144,7 +163,7 @@ bool _isSpin; }; - + ////////////////////////////////////////////////////////////////////// // Scale animation installer ////////////////////////////////////////////////////////////////////// @@ -162,7 +181,7 @@ SGVec3d _center; }; - + ////////////////////////////////////////////////////////////////////// // dist scale animation installer ////////////////////////////////////////////////////////////////////// @@ -175,7 +194,7 @@ class Transform; }; - + ////////////////////////////////////////////////////////////////////// // dist scale animation installer ////////////////////////////////////////////////////////////////////// @@ -189,7 +208,7 @@ class Transform; }; - + ////////////////////////////////////////////////////////////////////// // dist scale animation installer ////////////////////////////////////////////////////////////////////// @@ -202,7 +221,7 @@ class Transform; }; - + ////////////////////////////////////////////////////////////////////// // Range animation installer ////////////////////////////////////////////////////////////////////// @@ -220,7 +239,7 @@ SGVec2d _initialValue; }; - + ////////////////////////////////////////////////////////////////////// // Select animation installer ////////////////////////////////////////////////////////////////////// @@ -232,7 +251,7 @@ virtual osg::Group* createAnimationGroup(osg::Group& parent); }; - + ////////////////////////////////////////////////////////////////////// // Alpha test animation installer ////////////////////////////////////////////////////////////////////// @@ -244,7 +263,7 @@ virtual void install(osg::Node& node); }; - + ////////////////////////////////////////////////////////////////////// // Blend animation installer ////////////////////////////////////////////////////////////////////// @@ -261,7 +280,7 @@ SGSharedPtr _animationValue; }; - + ////////////////////////////////////////////////////////////////////// // Timed animation installer ////////////////////////////////////////////////////////////////////// @@ -275,7 +294,7 @@ class UpdateCallback; }; - + ////////////////////////////////////////////////////////////////////// // Shadow animation installer ////////////////////////////////////////////////////////////////////// @@ -289,7 +308,7 @@ class UpdateCallback; }; - + ////////////////////////////////////////////////////////////////////// // TextureTransform animation ////////////////////////////////////////////////////////////////////// @@ -310,7 +329,7 @@ UpdateCallback* updateCallback); }; - + ////////////////////////////////////////////////////////////////////// // Shader animation ////////////////////////////////////////////////////////////////////// @@ -326,22 +345,6 @@ osg::ref_ptr _effect_texture; }; - -////////////////////////////////////////////////////////////////////// -// Pick animation -////////////////////////////////////////////////////////////////////// - -class SGPickAnimation : public SGAnimation { -public: - SGPickAnimation(const SGPropertyNode* configNode, - SGPropertyNode* modelRoot); - virtual osg::Group* createAnimationGroup(osg::Group& parent); -private: - class PickCallback; - class VncCallback; -}; - - ////////////////////////////////////////////////////////////////////// // Light animation ////////////////////////////////////////////////////////////////////// @@ -351,11 +354,11 @@ SGLightAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const osgDB::Options* options, - const string &path, int i); + const std::string &path, int i); virtual osg::Group* createAnimationGroup(osg::Group& parent); virtual void install(osg::Node& node); private: - string _light_type; + std::string _light_type; SGVec3d _position; SGVec3d _direction; SGVec4d _ambient; @@ -366,7 +369,7 @@ double _cutoff; double _near; double _far; - string _key; + std::string _key; class UpdateCallback; friend class UpdateCallback; SGSharedPtr _animationValue; diff -Nru simgear-2.10.0/simgear/scene/model/animation_test.cxx simgear-3.0.0/simgear/scene/model/animation_test.cxx --- simgear-2.10.0/simgear/scene/model/animation_test.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/animation_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,69 @@ +#include "animation.hxx" + +#include +#include + +#define VERIFY_CLOSE(a, b) \ + if( norm((a) - (b)) > 1e-5 ) \ + { \ + std::cerr << "line " << __LINE__ << ": failed: "\ + << #a << " != " << #b\ + << " [" << (a) << " != " << (b) << "]" << std::endl; \ + return 1; \ + } + +#define VERIFY(a) \ + if( !(a) ) \ + { \ + std::cerr << "failed: line " << __LINE__ << ": " << #a << std::endl; \ + return 1; \ + } + +struct AnimationTest: + public SGAnimation +{ + AnimationTest(const SGPropertyNode* n): + SGAnimation(n, 0) + {} + + void readConfig() + { + readRotationCenterAndAxis(center, axis); + } + + SGVec3d center, + axis; +}; + +int main(int argc, char* argv[]) +{ + SGPropertyNode_ptr config = new SGPropertyNode; + AnimationTest anim(config); + + SGVec3d v1(1, 2, 3), + v2(-1, 4, 0); + config->setDoubleValue("axis/x1-m", v1.x()); + config->setDoubleValue("axis/y1-m", v1.y()); + config->setDoubleValue("axis/z1-m", v1.z()); + config->setDoubleValue("axis/x2-m", v2.x()); + config->setDoubleValue("axis/y2-m", v2.y()); + config->setDoubleValue("axis/z2-m", v2.z()); + anim.readConfig(); + + VERIFY_CLOSE(anim.center, (v1 + v2) * 0.5) + VERIFY_CLOSE(anim.axis, normalize(v2 - v1)) + + config->removeChild("axis", 0, false); + config->setDoubleValue("center/x-m", v1.x()); + config->setDoubleValue("center/y-m", v1.y()); + config->setDoubleValue("center/z-m", v1.z()); + config->setDoubleValue("axis/x", v2.x()); + config->setDoubleValue("axis/y", v2.y()); + config->setDoubleValue("axis/z", v2.z()); + anim.readConfig(); + + VERIFY_CLOSE(anim.center, v1) + VERIFY_CLOSE(anim.axis, normalize(v2)) + + return 0; +} diff -Nru simgear-2.10.0/simgear/scene/model/CMakeLists.txt simgear-3.0.0/simgear/scene/model/CMakeLists.txt --- simgear-2.10.0/simgear/scene/model/CMakeLists.txt 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -11,11 +11,13 @@ SGClipGroup.hxx SGInteractionAnimation.hxx SGMaterialAnimation.hxx + SGPickAnimation.hxx SGOffsetTransform.hxx SGReaderWriterXML.hxx SGRotateTransform.hxx SGScaleTransform.hxx SGText.hxx + SGTrackToAnimation.hxx SGTranslateTransform.hxx animation.hxx model.hxx @@ -34,12 +36,14 @@ SGClipGroup.cxx SGInteractionAnimation.cxx SGLightAnimation.cxx + SGPickAnimation.cxx SGMaterialAnimation.cxx SGOffsetTransform.cxx SGReaderWriterXML.cxx SGRotateTransform.cxx SGScaleTransform.cxx SGText.cxx + SGTrackToAnimation.cxx SGTranslateTransform.cxx animation.cxx model.cxx @@ -51,3 +55,11 @@ ) simgear_scene_component(model scene/model "${SOURCES}" "${HEADERS}") + +if(ENABLE_TESTS) + + add_executable(test_animations animation_test.cxx) + target_link_libraries(test_animations ${TEST_LIBS} ${OPENSCENEGRAPH_LIBRARIES}) + add_test(animations ${EXECUTABLE_OUTPUT_PATH}/test_animations) + +endif(ENABLE_TESTS) \ No newline at end of file diff -Nru simgear-2.10.0/simgear/scene/model/modellib.cxx simgear-3.0.0/simgear/scene/model/modellib.cxx --- simgear-2.10.0/simgear/scene/model/modellib.cxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/modellib.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -57,6 +57,11 @@ static_propRoot = root; } +void SGModelLib::resetPropertyRoot() +{ + static_propRoot.clear(); +} + void SGModelLib::setPanelFunc(panel_func pf) { static_panelFunc = pf; diff -Nru simgear-2.10.0/simgear/scene/model/modellib.hxx simgear-3.0.0/simgear/scene/model/modellib.hxx --- simgear-2.10.0/simgear/scene/model/modellib.hxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/modellib.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -46,6 +46,8 @@ static void init(const std::string &root_dir, SGPropertyNode* root); + static void resetPropertyRoot(); + static void setPanelFunc(panel_func pf); // Load a 3D model (any format) @@ -93,6 +95,7 @@ virtual ~SGModelData() {} virtual void modelLoaded(const std::string& path, SGPropertyNode *prop, osg::Node* branch) = 0; + virtual SGModelData* clone() const = 0; }; } diff -Nru simgear-2.10.0/simgear/scene/model/particles.cxx simgear-3.0.0/simgear/scene/model/particles.cxx --- simgear-2.10.0/simgear/scene/model/particles.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/particles.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -44,10 +44,6 @@ #include "particles.hxx" -#if SG_OSG_VERSION >= 27004 -#define OSG_PARTICLE_FIX 1 -#endif - namespace simgear { void GlobalParticleCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) @@ -192,19 +188,12 @@ osg::Geode* g = new osg::Geode; align->addChild(g); g->addDrawable(particleSys); -#ifndef OSG_PARTICLE_FIX - emitter->setReferenceFrame(osgParticle::Emitter::ABSOLUTE_RF); -#endif } else { -#ifdef OSG_PARTICLE_FIX callback()->particleFrame = new osg::MatrixTransform(); osg::Geode* g = new osg::Geode; g->addDrawable(particleSys); callback()->particleFrame->addChild(g); getCommonRoot()->addChild(callback()->particleFrame.get()); -#else - getCommonGeode()->addDrawable(particleSys); -#endif } std::string textureFile; if (configNode->hasValue("texture")) { @@ -477,14 +466,7 @@ program->setFluidToWater(); if (programnode->getBoolValue("gravity", true)) { -#ifdef OSG_PARTICLE_FIX program->setToGravity(); -#else - if (attach == "world") - callback()->setupProgramGravity(true); - else - program->setToGravity(); -#endif } else program->setAcceleration(osg::Vec3(0,0,0)); @@ -545,7 +527,7 @@ particleSys->getDefaultParticleTemplate().setSizeRange(osgParticle::rangef(startSize, endSize)); if (lifeValue) particleSys->getDefaultParticleTemplate().setLifeTime(lifeValue->getValue()); -#ifdef OSG_PARTICLE_FIX + if (particleFrame.valid()) { MatrixList mlist = node->getWorldMatrices(); if (!mlist.empty()) { @@ -568,13 +550,5 @@ } if (program.valid() && useWind) program->setWind(_wind); -#else - if (program.valid()) { - if (useGravity) - program->setAcceleration(GlobalParticleCallback::getGravityVector()); - if (useWind) - program->setWind(GlobalParticleCallback::getWindVector()); - } -#endif } } // namespace simgear diff -Nru simgear-2.10.0/simgear/scene/model/placement.cxx simgear-3.0.0/simgear/scene/model/placement.cxx --- simgear-2.10.0/simgear/scene/model/placement.cxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/placement.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -36,8 +36,8 @@ void SGModelPlacement::init( osg::Node * model ) { - // remove previous model (in case of reinit) - _transform->removeChild(0,1); + // remove previous models (in case of reinit) + _transform->removeChild(0, _transform->getNumChildren()); if (model != 0) { _transform->addChild(model); } @@ -45,6 +45,20 @@ } void +SGModelPlacement::add( osg::Node* model ) +{ + if (model != 0) { + _transform->addChild(model); + } +} + +void SGModelPlacement::clear() +{ + _selector = NULL; + _transform = NULL; +} + +void SGModelPlacement::update() { // The cartesian position @@ -75,30 +89,6 @@ } void -SGModelPlacement::setLongitudeDeg (double lon_deg) -{ - _position.setLongitudeDeg(lon_deg); -} - -void -SGModelPlacement::setLatitudeDeg (double lat_deg) -{ - _position.setLatitudeDeg(lat_deg); -} - -void -SGModelPlacement::setElevationFt (double elev_ft) -{ - _position.setElevationFt(elev_ft); -} - -void -SGModelPlacement::setPosition (double lon_deg, double lat_deg, double elev_ft) -{ - _position = SGGeod::fromDegFt(lon_deg, lat_deg, elev_ft); -} - -void SGModelPlacement::setPosition(const SGGeod& position) { _position = position; diff -Nru simgear-2.10.0/simgear/scene/model/placement.hxx simgear-3.0.0/simgear/scene/model/placement.hxx --- simgear-2.10.0/simgear/scene/model/placement.hxx 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/placement.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -42,7 +42,9 @@ virtual ~SGModelPlacement (); virtual void init( osg::Node* model ); - + void clear(); + void add( osg::Node* model ); + virtual void update(); virtual osg::Node* getSceneGraph () { return _selector.get(); } @@ -50,14 +52,6 @@ virtual bool getVisible () const; virtual void setVisible (bool visible); - virtual double getLongitudeDeg () const { return _position.getLongitudeDeg(); } - virtual double getLatitudeDeg () const { return _position.getLatitudeDeg(); } - virtual double getElevationFt () const { return _position.getElevationFt(); } - - virtual void setLongitudeDeg (double lon_deg); - virtual void setLatitudeDeg (double lat_deg); - virtual void setElevationFt (double elev_ft); - virtual void setPosition (double lon_deg, double lat_deg, double elev_ft); void setPosition(const SGGeod& position); const SGGeod& getPosition() const { return _position; } diff -Nru simgear-2.10.0/simgear/scene/model/SGLightAnimation.cxx simgear-3.0.0/simgear/scene/model/SGLightAnimation.cxx --- simgear-2.10.0/simgear/scene/model/SGLightAnimation.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/SGLightAnimation.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -36,7 +36,7 @@ #include #include -typedef std::map > EffectMap; +typedef std::map > EffectMap; static EffectMap lightEffectMap; #define GET_COLOR_VALUE(n) \ @@ -96,7 +96,7 @@ SGLightAnimation::SGLightAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, const osgDB::Options* options, - const string &path, int i) : + const std::string &path, int i) : SGAnimation(configNode, modelRoot), _options(options) { @@ -113,7 +113,7 @@ _cutoff = getConfig()->getDoubleValue("cutoff"); _near = getConfig()->getDoubleValue("near-m"); _far = getConfig()->getDoubleValue("far-m"); - _key = path + ";" + boost::lexical_cast( i ); + _key = path + ";" + boost::lexical_cast( i ); SGConstPropertyNode_ptr dim_factor = configNode->getChild("dim-factor"); if (dim_factor.valid()) { diff -Nru simgear-2.10.0/simgear/scene/model/SGMaterialAnimation.hxx simgear-3.0.0/simgear/scene/model/SGMaterialAnimation.hxx --- simgear-2.10.0/simgear/scene/model/SGMaterialAnimation.hxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/SGMaterialAnimation.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -23,7 +23,7 @@ public: SGMaterialAnimation(const SGPropertyNode* configNode, SGPropertyNode* modelRoot, - const osgDB::Options* options,const string &path); + const osgDB::Options* options,const std::string &path); virtual osg::Group* createAnimationGroup(osg::Group& parent); virtual void install(osg::Node& node); static SGPropertyNode_ptr makeEffectProperties(const SGPropertyNode* animProp); diff -Nru simgear-2.10.0/simgear/scene/model/SGPickAnimation.cxx simgear-3.0.0/simgear/scene/model/SGPickAnimation.cxx --- simgear-2.10.0/simgear/scene/model/SGPickAnimation.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/SGPickAnimation.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,833 @@ +/* -*-c++-*- + * + * Copyright (C) 2013 James Turner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace simgear; + +using OpenThreads::Mutex; +using OpenThreads::ScopedLock; + +static void readOptionalBindingList(const SGPropertyNode* aNode, SGPropertyNode* modelRoot, + const std::string& aName, SGBindingList& aBindings) +{ + const SGPropertyNode* n = aNode->getChild(aName); + if (n) + aBindings = readBindingList(n->getChildren("binding"), modelRoot); + +} + + +osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter& ea) +{ + using namespace osg; + const GraphicsContext* gc = ea.getGraphicsContext(); + const GraphicsContext::Traits* traits = gc->getTraits() ; + // Scale x, y to the dimensions of the window + double x = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin())) + * (double)traits->width); + double y = (((ea.getY() - ea.getYmin()) / (ea.getYmax() - ea.getYmin())) + * (double)traits->height); + if (ea.getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS) + y = (double)traits->height - y; + + return osg::Vec2d(x, y); +} + + class SGPickAnimation::PickCallback : public SGPickCallback { + public: + PickCallback(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot) : + SGPickCallback(PriorityPanel), + _repeatable(configNode->getBoolValue("repeatable", false)), + _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)) + { + std::vector bindings; + + bindings = configNode->getChildren("button"); + for (unsigned int i = 0; i < bindings.size(); ++i) { + _buttons.insert( bindings[i]->getIntValue() ); + } + + _bindingsDown = readBindingList(configNode->getChildren("binding"), modelRoot); + readOptionalBindingList(configNode, modelRoot, "mod-up", _bindingsUp); + + + if (configNode->hasChild("cursor")) { + _cursorName = configNode->getStringValue("cursor"); + } + } + + void addHoverBindings(const SGPropertyNode* hoverNode, + SGPropertyNode* modelRoot) + { + _hover = readBindingList(hoverNode->getChildren("binding"), modelRoot); + } + + virtual bool buttonPressed( int button, + const osgGA::GUIEventAdapter&, + const Info& ) + { + if (_buttons.find(button) == _buttons.end()) { + return false; + } + + fireBindingList(_bindingsDown); + _repeatTime = -_repeatInterval; // anti-bobble: delay start of repeat + return true; + } + virtual void buttonReleased( int keyModState, + const osgGA::GUIEventAdapter&, + const Info* ) + { + SG_UNUSED(keyModState); + fireBindingList(_bindingsUp); + } + + virtual void update(double dt, int keyModState) + { + SG_UNUSED(keyModState); + if (!_repeatable) + return; + + _repeatTime += dt; + while (_repeatInterval < _repeatTime) { + _repeatTime -= _repeatInterval; + fireBindingList(_bindingsDown); + } + } + + virtual bool hover( const osg::Vec2d& windowPos, + const Info& ) + { + if (_hover.empty()) { + return false; + } + + SGPropertyNode_ptr params(new SGPropertyNode); + params->setDoubleValue("x", windowPos.x()); + params->setDoubleValue("y", windowPos.y()); + fireBindingList(_hover, params.ptr()); + return true; + } + + std::string getCursor() const + { return _cursorName; } + private: + SGBindingList _bindingsDown; + SGBindingList _bindingsUp; + SGBindingList _hover; + std::set _buttons; + bool _repeatable; + double _repeatInterval; + double _repeatTime; + std::string _cursorName; + }; + + class VncVisitor : public osg::NodeVisitor { + public: + VncVisitor(double x, double y, int mask) : + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), + _texX(x), _texY(y), _mask(mask), _done(false) + { + SG_LOG(SG_INPUT, SG_DEBUG, "VncVisitor constructor " + << x << "," << y << " mask " << mask); + } + + virtual void apply(osg::Node &node) + { + // Some nodes have state sets attached + touchStateSet(node.getStateSet()); + if (!_done) + traverse(node); + if (_done) return; + // See whether we are a geode worth exploring + osg::Geode *g = dynamic_cast(&node); + if (!g) return; + // Go find all its drawables + int i = g->getNumDrawables(); + while (--i >= 0) { + osg::Drawable *d = g->getDrawable(i); + if (d) touchDrawable(*d); + } + // Out of optimism, do the same for EffectGeode + simgear::EffectGeode *eg = dynamic_cast(&node); + if (!eg) return; + for (simgear::EffectGeode::DrawablesIterator di = eg->drawablesBegin(); + di != eg->drawablesEnd(); di++) { + touchDrawable(**di); + } + // Now see whether the EffectGeode has an Effect + simgear::Effect *e = eg->getEffect(); + if (e) { + touchStateSet(e->getDefaultStateSet()); + } + } + + inline void touchDrawable(osg::Drawable &d) + { + osg::StateSet *ss = d.getStateSet(); + touchStateSet(ss); + } + + void touchStateSet(osg::StateSet *ss) + { + if (!ss) return; + osg::StateAttribute *sa = ss->getTextureAttribute(0, + osg::StateAttribute::TEXTURE); + if (!sa) return; + osg::Texture *t = sa->asTexture(); + if (!t) return; + osg::Image *img = t->getImage(0); + if (!img) return; + if (!_done) { + int pixX = _texX * img->s(); + int pixY = _texY * img->t(); + _done = img->sendPointerEvent(pixX, pixY, _mask); + SG_LOG(SG_INPUT, SG_DEBUG, "VncVisitor image said " << _done + << " to coord " << pixX << "," << pixY); + } + } + + inline bool wasSuccessful() + { + return _done; + } + + private: + double _texX, _texY; + int _mask; + bool _done; + }; + +/////////////////////////////////////////////////////////////////////////////// + +class SGPickAnimation::VncCallback : public SGPickCallback { +public: + VncCallback(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot, + osg::Group *node) + : _node(node) + { + SG_LOG(SG_INPUT, SG_DEBUG, "Configuring VNC callback"); + const char *cornernames[3] = {"top-left", "top-right", "bottom-left"}; + SGVec3d *cornercoords[3] = {&_topLeft, &_toRight, &_toDown}; + for (int c =0; c < 3; c++) { + const SGPropertyNode* cornerNode = configNode->getChild(cornernames[c]); + *cornercoords[c] = SGVec3d( + cornerNode->getDoubleValue("x"), + cornerNode->getDoubleValue("y"), + cornerNode->getDoubleValue("z")); + } + _toRight -= _topLeft; + _toDown -= _topLeft; + _squaredRight = dot(_toRight, _toRight); + _squaredDown = dot(_toDown, _toDown); + } + + virtual bool buttonPressed( int button, + const osgGA::GUIEventAdapter&, + const Info& info ) + { + SGVec3d loc(info.local); + SG_LOG(SG_INPUT, SG_DEBUG, "VNC pressed " << button << ": " << loc); + loc -= _topLeft; + _x = dot(loc, _toRight) / _squaredRight; + _y = dot(loc, _toDown) / _squaredDown; + if (_x<0) _x = 0; else if (_x > 1) _x = 1; + if (_y<0) _y = 0; else if (_y > 1) _y = 1; + VncVisitor vv(_x, _y, 1 << button); + _node->accept(vv); + return vv.wasSuccessful(); + + } + virtual void buttonReleased( int keyModState, + const osgGA::GUIEventAdapter&, + const Info* ) + { + SG_UNUSED(keyModState); + SG_LOG(SG_INPUT, SG_DEBUG, "VNC release"); + VncVisitor vv(_x, _y, 0); + _node->accept(vv); + } + +private: + double _x, _y; + osg::ref_ptr _node; + SGVec3d _topLeft, _toRight, _toDown; + double _squaredRight, _squaredDown; +}; + +/////////////////////////////////////////////////////////////////////////////// + +SGPickAnimation::SGPickAnimation(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot) : + SGAnimation(configNode, modelRoot) +{ + std::vector names = + configNode->getChildren("proxy-name"); + for (unsigned i = 0; i < names.size(); ++i) { + _proxyNames.push_back(names[i]->getStringValue()); + } +} + +void SGPickAnimation::apply(osg::Node* node) +{ + SGAnimation::apply(node); +} + +namespace +{ +OpenThreads::Mutex highlightStateSetMutex; +osg::ref_ptr static_highlightStateSet; +} + + + + +osg::StateSet* sharedHighlightStateSet() +{ + ScopedLock lock(highlightStateSetMutex); + if (!static_highlightStateSet.valid()) { + static_highlightStateSet = new osg::StateSet; + + osg::Texture2D* white = StateAttributeFactory::instance()->getWhiteTexture(); + static_highlightStateSet->setTextureAttributeAndModes(0, white, + (osg::StateAttribute::ON + | osg::StateAttribute::OVERRIDE + | osg::StateAttribute::PROTECTED)); + osg::PolygonOffset* polygonOffset = new osg::PolygonOffset; + polygonOffset->setFactor(-1); + polygonOffset->setUnits(-1); + static_highlightStateSet->setAttribute(polygonOffset, osg::StateAttribute::OVERRIDE); + static_highlightStateSet->setMode(GL_POLYGON_OFFSET_LINE, + osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE); + osg::PolygonMode* polygonMode = new osg::PolygonMode; + polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK, + osg::PolygonMode::LINE); + static_highlightStateSet->setAttribute(polygonMode, osg::StateAttribute::OVERRIDE); + osg::Material* material = new osg::Material; + material->setColorMode(osg::Material::OFF); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 1)); + // XXX Alpha < 1.0 in the diffuse material value is a signal to the + // default shader to take the alpha value from the material value + // and not the glColor. In many cases the pick animation geometry is + // transparent, so the outline would not be visible without this hack. + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, .95)); + material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1, 1, 0, 1)); + material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0, 0, 0, 0)); + static_highlightStateSet->setAttribute( + material, osg::StateAttribute::OVERRIDE | osg::StateAttribute::PROTECTED); + // The default shader has a colorMode uniform that mimics the + // behavior of Material color mode. + + osg::Uniform* colorModeUniform = new osg::Uniform(osg::Uniform::INT, "colorMode"); + colorModeUniform->set(0); // MODE_OFF + colorModeUniform->setDataVariance(osg::Object::STATIC); + static_highlightStateSet->addUniform(colorModeUniform, + osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); + } + + return static_highlightStateSet.get(); +} + +void +SGPickAnimation::apply(osg::Group& group) +{ + if (_objectNames.empty() && _proxyNames.empty()) { + return; + } + + group.traverse(*this); + + // iterate over all group children + int i = group.getNumChildren() - 1; + for (; 0 <= i; --i) { + osg::Node* child = group.getChild(i); + if (child->getName().empty()) { + continue; + } + + std::list::iterator it = std::find(_objectNames.begin(), _objectNames.end(), child->getName()); + if (it != _objectNames.end()) { + //_objectNames.erase(it); + install(*child); + + osg::ref_ptr renderGroup, pickGroup; + osg::Group* mainGroup = createMainGroup(&group); + mainGroup->setName(child->getName()); + child->setName(""); // don't apply other animations twice + + if (getConfig()->getBoolValue("visible", true)) { + renderGroup = new osg::Group; + renderGroup->setName("pick render group"); + renderGroup->addChild(child); + mainGroup->addChild(renderGroup); + } + + pickGroup = new osg::Group; + pickGroup->setName("pick highlight group"); + pickGroup->setNodeMask(simgear::PICK_BIT); + pickGroup->setStateSet(sharedHighlightStateSet()); + mainGroup->addChild(pickGroup); + + setupCallbacks(SGSceneUserData::getOrCreateSceneUserData(mainGroup), mainGroup); + + pickGroup->addChild(child); + group.removeChild(child); + continue; + } + + string_list::iterator j = std::find(_proxyNames.begin(), _proxyNames.end(), child->getName()); + if (j == _proxyNames.end()) { + continue; + } + + _proxyNames.erase(j); + osg::ref_ptr proxyGroup = new osg::Group; + group.addChild(proxyGroup); + proxyGroup->setStateSet(sharedHighlightStateSet()); + proxyGroup->setNodeMask(simgear::PICK_BIT); + + setupCallbacks(SGSceneUserData::getOrCreateSceneUserData(proxyGroup), proxyGroup); + proxyGroup->addChild(child); + group.removeChild(child); + } // of group children iteration +} + +osg::Group* +SGPickAnimation::createMainGroup(osg::Group* pr) +{ + osg::Group* g = new osg::Group; + pr->addChild(g); + return g; +} + +void +SGPickAnimation::setupCallbacks(SGSceneUserData* ud, osg::Group* parent) +{ + PickCallback* pickCb = NULL; + + // add actions that become macro and command invocations + std::vector actions; + actions = getConfig()->getChildren("action"); + for (unsigned int i = 0; i < actions.size(); ++i) { + pickCb = new PickCallback(actions[i], getModelRoot()); + ud->addPickCallback(pickCb); + } + + if (getConfig()->hasChild("hovered")) { + if (!pickCb) { + // make a trivial PickCallback to hang the hovered off of + SGPropertyNode_ptr dummyNode(new SGPropertyNode); + pickCb = new PickCallback(dummyNode.ptr(), getModelRoot()); + ud->addPickCallback(pickCb); + } + + pickCb->addHoverBindings(getConfig()->getNode("hovered"), getModelRoot()); + } + + // Look for the VNC sessions that want raw mouse input + actions = getConfig()->getChildren("vncaction"); + for (unsigned int i = 0; i < actions.size(); ++i) { + ud->addPickCallback(new VncCallback(actions[i], getModelRoot(), parent)); + } +} + +/////////////////////////////////////////////////////////////////////////// + +// insert count copies of binding list A, into the output list. +// effectively makes the output list fire binding A multiple times +// in sequence +static void repeatBindings(const SGBindingList& a, SGBindingList& out, int count) +{ + out.clear(); + for (int i=0; igetDoubleValue("interval-sec", 0.1)), + _dragDirection(DRAG_DEFAULT) + { + readOptionalBindingList(configNode, modelRoot, "action", _action); + readOptionalBindingList(configNode, modelRoot, "increase", _bindingsIncrease); + readOptionalBindingList(configNode, modelRoot, "decrease", _bindingsDecrease); + + readOptionalBindingList(configNode, modelRoot, "release", _releaseAction); + readOptionalBindingList(configNode, modelRoot, "hovered", _hover); + + if (configNode->hasChild("shift-action") || configNode->hasChild("shift-increase") || + configNode->hasChild("shift-decrease")) + { + // explicit shifted behaviour - just do exactly what was provided + readOptionalBindingList(configNode, modelRoot, "shift-action", _shiftedAction); + readOptionalBindingList(configNode, modelRoot, "shift-increase", _shiftedIncrease); + readOptionalBindingList(configNode, modelRoot, "shift-decrease", _shiftedDecrease); + } else { + // default shifted behaviour - repeat normal bindings N times. + int shiftRepeat = configNode->getIntValue("shift-repeat", 10); + repeatBindings(_action, _shiftedAction, shiftRepeat); + repeatBindings(_bindingsIncrease, _shiftedIncrease, shiftRepeat); + repeatBindings(_bindingsDecrease, _shiftedDecrease, shiftRepeat); + } // of default shifted behaviour + + _dragScale = configNode->getDoubleValue("drag-scale-px", 10.0); + std::string dragDir = configNode->getStringValue("drag-direction"); + if (dragDir == "vertical") { + _dragDirection = DRAG_VERTICAL; + } else if (dragDir == "horizontal") { + _dragDirection = DRAG_HORIZONTAL; + } + + if (configNode->hasChild("cursor")) { + _cursorName = configNode->getStringValue("cursor"); + } else { + DragDirection dir = effectiveDragDirection(); + if (dir == DRAG_VERTICAL) { + _cursorName = "drag-vertical"; + } else if (dir == DRAG_HORIZONTAL) { + _cursorName = "drag-horizontal"; + } + } + } + + virtual bool buttonPressed( int button, + const osgGA::GUIEventAdapter& ea, + const Info& ) + { + // the 'be nice to Mac / laptop' users option; alt-clicking spins the + // opposite direction. Should make this configurable + if ((button == 0) && (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_ALT)) { + button = 1; + } + + int increaseMouseWheel = static_knobMouseWheelAlternateDirection ? 3 : 4; + int decreaseMouseWheel = static_knobMouseWheelAlternateDirection ? 4 : 3; + + _direction = DIRECTION_NONE; + if ((button == 0) || (button == increaseMouseWheel)) { + _direction = DIRECTION_INCREASE; + } else if ((button == 1) || (button == decreaseMouseWheel)) { + _direction = DIRECTION_DECREASE; + } else { + return false; + } + + _lastFirePos = eventToWindowCoords(ea); + // delay start of repeat, makes dragging more usable + _repeatTime = -_repeatInterval; + _hasDragged = false; + return true; + } + + virtual void buttonReleased( int keyModState, + const osgGA::GUIEventAdapter&, + const Info* ) + { + // for *clicks*, we only fire on button release + if (!_hasDragged) { + fire(keyModState & osgGA::GUIEventAdapter::MODKEY_SHIFT, _direction); + } + + fireBindingList(_releaseAction); + } + + DragDirection effectiveDragDirection() const + { + if (_dragDirection == DRAG_DEFAULT) { + // respect the current default settings - this allows runtime + // setting of the default drag direction. + return static_knobDragAlternateAxis ? DRAG_VERTICAL : DRAG_HORIZONTAL; + } + + return _dragDirection; + } + + virtual void mouseMoved( const osgGA::GUIEventAdapter& ea, + const Info* ) + { + _mousePos = eventToWindowCoords(ea); + osg::Vec2d deltaMouse = _mousePos - _lastFirePos; + + if (!_hasDragged) { + + double manhattanDist = deltaMouse.x() * deltaMouse.x() + deltaMouse.y() * deltaMouse.y(); + if (manhattanDist < 5) { + // don't do anything, just input noise + return; + } + + // user is dragging, disable repeat behaviour + _hasDragged = true; + } + + double delta = (effectiveDragDirection() == DRAG_VERTICAL) ? deltaMouse.y() : deltaMouse.x(); + // per-animation scale factor lets the aircraft author tune for expectations, + // eg heading setting vs 5-state switch. + // then we scale by a global sensitivity, which the user can set. + delta *= static_dragSensitivity / _dragScale; + + if (fabs(delta) >= 1.0) { + // determine direction from sign of delta + Direction dir = (delta > 0.0) ? DIRECTION_INCREASE : DIRECTION_DECREASE; + fire(ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_SHIFT, dir); + _lastFirePos = _mousePos; + } + } + + virtual void update(double dt, int keyModState) + { + if (_hasDragged) { + return; + } + + _repeatTime += dt; + while (_repeatInterval < _repeatTime) { + _repeatTime -= _repeatInterval; + fire(keyModState & osgGA::GUIEventAdapter::MODKEY_SHIFT, _direction); + } // of repeat iteration + } + + virtual bool hover( const osg::Vec2d& windowPos, + const Info& ) + { + if (_hover.empty()) { + return false; + } + + SGPropertyNode_ptr params(new SGPropertyNode); + params->setDoubleValue("x", windowPos.x()); + params->setDoubleValue("y", windowPos.y()); + fireBindingList(_hover, params.ptr()); + return true; + } + + void setCursor(const std::string& aName) + { + _cursorName = aName; + } + + virtual std::string getCursor() const + { return _cursorName; } + +private: + void fire(bool isShifted, Direction dir) + { + const SGBindingList& act(isShifted ? _shiftedAction : _action); + const SGBindingList& incr(isShifted ? _shiftedIncrease : _bindingsIncrease); + const SGBindingList& decr(isShifted ? _shiftedDecrease : _bindingsDecrease); + + switch (dir) { + case DIRECTION_INCREASE: + fireBindingListWithOffset(act, 1, 1); + fireBindingList(incr); + break; + case DIRECTION_DECREASE: + fireBindingListWithOffset(act, -1, 1); + fireBindingList(decr); + break; + default: break; + } + } + + SGBindingList _action, _shiftedAction; + SGBindingList _releaseAction; + SGBindingList _bindingsIncrease, _shiftedIncrease, + _bindingsDecrease, _shiftedDecrease; + SGBindingList _hover; + + + Direction _direction; + double _repeatInterval; + double _repeatTime; + + DragDirection _dragDirection; + bool _hasDragged; ///< has the mouse been dragged since the press? + osg::Vec2d _mousePos, ///< current window coords location of the mouse + _lastFirePos; ///< mouse location where we last fired the bindings + double _dragScale; + + std::string _cursorName; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class SGKnobAnimation::UpdateCallback : public osg::NodeCallback { +public: + UpdateCallback(SGExpressiond const* animationValue) : + _animationValue(animationValue) + { + setName("SGKnobAnimation::UpdateCallback"); + } + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + SGRotateTransform* transform = static_cast(node); + transform->setAngleDeg(_animationValue->getValue()); + traverse(node, nv); + } + +private: + SGSharedPtr _animationValue; +}; + + +SGKnobAnimation::SGKnobAnimation(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot) : + SGPickAnimation(configNode, modelRoot) +{ + SGSharedPtr value = read_value(configNode, modelRoot, "-deg", + -SGLimitsd::max(), SGLimitsd::max()); + _animationValue = value->simplify(); + + + readRotationCenterAndAxis(_center, _axis); +} + +osg::Group* +SGKnobAnimation::createMainGroup(osg::Group* pr) +{ + SGRotateTransform* transform = new SGRotateTransform(); + + UpdateCallback* uc = new UpdateCallback(_animationValue); + transform->setUpdateCallback(uc); + transform->setCenter(_center); + transform->setAxis(_axis); + + pr->addChild(transform); + return transform; +} + +void +SGKnobAnimation::setupCallbacks(SGSceneUserData* ud, osg::Group*) +{ + ud->setPickCallback(new KnobSliderPickCallback(getConfig(), getModelRoot())); +} + +void SGKnobAnimation::setAlternateMouseWheelDirection(bool aToggle) +{ + static_knobMouseWheelAlternateDirection = aToggle; +} + +void SGKnobAnimation::setAlternateDragAxis(bool aToggle) +{ + static_knobDragAlternateAxis = aToggle; +} + +void SGKnobAnimation::setDragSensitivity(double aFactor) +{ + static_dragSensitivity = aFactor; +} + +/////////////////////////////////////////////////////////////////////////////// + +class SGSliderAnimation::UpdateCallback : public osg::NodeCallback { +public: + UpdateCallback(SGExpressiond const* animationValue) : + _animationValue(animationValue) + { + setName("SGSliderAnimation::UpdateCallback"); + } + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + SGTranslateTransform* transform = static_cast(node); + transform->setValue(_animationValue->getValue()); + + traverse(node, nv); + } + +private: + SGSharedPtr _animationValue; +}; + + +SGSliderAnimation::SGSliderAnimation(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot) : + SGPickAnimation(configNode, modelRoot) +{ + SGSharedPtr value = read_value(configNode, modelRoot, "-m", + -SGLimitsd::max(), SGLimitsd::max()); + _animationValue = value->simplify(); + + _axis = readTranslateAxis(configNode); +} + +osg::Group* +SGSliderAnimation::createMainGroup(osg::Group* pr) +{ + SGTranslateTransform* transform = new SGTranslateTransform(); + + UpdateCallback* uc = new UpdateCallback(_animationValue); + transform->setUpdateCallback(uc); + transform->setAxis(_axis); + + pr->addChild(transform); + return transform; +} + +void +SGSliderAnimation::setupCallbacks(SGSceneUserData* ud, osg::Group*) +{ + ud->setPickCallback(new KnobSliderPickCallback(getConfig(), getModelRoot())); +} diff -Nru simgear-2.10.0/simgear/scene/model/SGPickAnimation.hxx simgear-3.0.0/simgear/scene/model/SGPickAnimation.hxx --- simgear-2.10.0/simgear/scene/model/SGPickAnimation.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/SGPickAnimation.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,121 @@ +/* -*-c++-*- + * + * Copyright (C) 2013 James Turner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef SG_SCENE_PICK_ANIMATION_HXX +#define SG_SCENE_PICK_ANIMATION_HXX + +#include +#include + +// forward decls +class SGPickCallback; +class SGSceneUserData; + +////////////////////////////////////////////////////////////////////// +// Pick animation +////////////////////////////////////////////////////////////////////// + +class SGPickAnimation : public SGAnimation { +public: + SGPickAnimation(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot); + + // override so we can treat object-name specially + virtual void apply(osg::Group& group); + + void apply(osg::Node* node); +protected: + + + virtual osg::Group* createMainGroup(osg::Group* pr); + + virtual void setupCallbacks(SGSceneUserData* ud, osg::Group* parent); +private: + class PickCallback; + class VncCallback; + + string_list _proxyNames; +}; + + +class SGKnobAnimation : public SGPickAnimation +{ +public: + SGKnobAnimation(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot); + + /** + * by default mouse wheel up corresponds to increment (CW) + * and mouse-wheel down corresponds to decrement (CCW). + * Since no one can agree on that, make it a global toggle. + */ + static void setAlternateMouseWheelDirection(bool aToggle); + + /** + * by default mouse is dragged left-right to change knobs. + * set this to true to default to up-down. Individual knobs + * can overrider this, + */ + static void setAlternateDragAxis(bool aToggle); + + + /** + * Scale the drag sensitivity. This provides a global hook for + * the user to scale the senstivity of dragging according to + * personal preference. + */ + static void setDragSensitivity(double aFactor); + + +protected: + virtual osg::Group* createMainGroup(osg::Group* pr); + + virtual void setupCallbacks(SGSceneUserData* ud, osg::Group* parent); + +private: + class UpdateCallback; + + SGVec3d _axis; + SGVec3d _center; + SGSharedPtr _animationValue; +}; + +class SGSliderAnimation : public SGPickAnimation +{ +public: + SGSliderAnimation(const SGPropertyNode* configNode, + SGPropertyNode* modelRoot); + + +protected: + virtual osg::Group* createMainGroup(osg::Group* pr); + + virtual void setupCallbacks(SGSceneUserData* ud, osg::Group* parent); + +private: + class UpdateCallback; + + SGVec3d _axis; + SGSharedPtr _animationValue; +}; + +#endif // of SG_SCENE_PICK_ANIMATION_HXX + diff -Nru simgear-2.10.0/simgear/scene/model/SGReaderWriterXML.cxx simgear-3.0.0/simgear/scene/model/SGReaderWriterXML.cxx --- simgear-2.10.0/simgear/scene/model/SGReaderWriterXML.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/SGReaderWriterXML.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -160,6 +160,7 @@ SGPropertyNode* typeProp = animProp->getChild("type"); if (!typeProp) continue; + const char* typeString = typeProp->getStringValue(); if (!strcmp(typeString, "material")) { effectProp @@ -214,6 +215,43 @@ osg::Node::NodeMask nodeMaskSet; osg::Node::NodeMask nodeMaskClear; }; + +} + +namespace { + class ExcludeInPreview + { + public: + bool operator()(SGPropertyNode* aNode) const + { + string typeString(aNode->getStringValue("type")); + // exclude these so we don't show yellow outlines in preview mode + return (typeString == "pick") || (typeString == "knob") || (typeString == "slider"); + } + }; + + bool removeNamedNode(osg::Group* aGroup, const std::string& aName) + { + int nKids = aGroup->getNumChildren(); + for (int i = 0; i < nKids; i++) { + osg::Node* child = aGroup->getChild(i); + if (child->getName() == aName) { + aGroup->removeChild(child); + return true; + } + } + + for (int i = 0; i < nKids; i++) { + osg::Group* childGroup = aGroup->getChild(i)->asGroup(); + if (!childGroup) + continue; + + if (removeNamedNode(childGroup, aName)) + return true; + } // of child groups traversal + + return false; + } } static osg::Node * @@ -243,7 +281,8 @@ osg::ref_ptr model; osg::ref_ptr group; SGPropertyNode_ptr props = new SGPropertyNode; - + bool previewMode = (dbOptions->getPluginStringData("SimGear::PREVIEW") == "ON"); + // Check for an XML wrapper if (modelpath.extension() == "xml") { try { @@ -256,6 +295,10 @@ if (overlay) copyProperties(overlay, props); + if (previewMode && props->hasChild("nopreview")) { + return NULL; + } + if (props->hasValue("/path")) { string modelPathStr = props->getStringValue("/path"); modelpath = SGModelLib::findDataFile(modelPathStr, NULL, modelDir); @@ -374,6 +417,9 @@ << "\n\tfrom:" << t.getOrigin()); continue; } + + if (!submodel) + continue; osg::ref_ptr submodel_final = submodel; SGPropertyNode *offs = sub_props->getNode("offsets", false); @@ -454,6 +500,13 @@ PropertyList effect_nodes = props->getChildren("effect"); PropertyList animation_nodes = props->getChildren("animation"); + + if (previewMode) { + PropertyList::iterator it; + it = std::remove_if(animation_nodes.begin(), animation_nodes.end(), ExcludeInPreview()); + animation_nodes.erase(it, animation_nodes.end()); + } + // Some material animations (eventually all) are actually effects. makeEffectAnimations(animation_nodes, effect_nodes); { @@ -462,11 +515,20 @@ group = static_cast(modelWithEffects.get()); } - for (unsigned i = 0; i < animation_nodes.size(); ++i) + for (unsigned i = 0; i < animation_nodes.size(); ++i) { + if (previewMode && animation_nodes[i]->hasChild("nopreview")) { + PropertyList names(animation_nodes[i]->getChildren("object-name")); + for (unsigned int n=0; ngetStringValue()); + } // of object-names in the animation + continue; + } + /// OSGFIXME: duh, why not only model????? SGAnimation::animate(group.get(), animation_nodes[i], prop_root, options.get(), path.str(), i); - + } + if (!needTransform && group->getNumChildren() < 2) { model = group->getChild(0); group->removeChild(model.get()); diff -Nru simgear-2.10.0/simgear/scene/model/SGText.cxx simgear-3.0.0/simgear/scene/model/SGText.cxx --- simgear-2.10.0/simgear/scene/model/SGText.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/SGText.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -20,10 +20,13 @@ # include #endif +#include + #include "SGText.hxx" #include #include +#include #include #include @@ -41,9 +44,9 @@ offset( aOffset ), truncate( aTruncate ), numeric( aNumeric ), - format( aFormat ) + format( simgear::strutils::sanitizePrintfFormat( aFormat ) ) { - if( format.size() == 0 ) { + if( format.empty() ) { if( numeric ) format = "%f"; else format = "%s"; } @@ -88,8 +91,6 @@ { SGConstPropertyNode_ptr p; - SG_LOG(SG_GENERAL, SG_DEBUG, "Creating a text object"); - osgText::Text * text = new osgText::Text(); osg::Geode * g = new osg::Geode; g->addDrawable( text ); diff -Nru simgear-2.10.0/simgear/scene/model/SGTrackToAnimation.cxx simgear-3.0.0/simgear/scene/model/SGTrackToAnimation.cxx --- simgear-2.10.0/simgear/scene/model/SGTrackToAnimation.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/SGTrackToAnimation.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,430 @@ +// TrackTo animation +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "SGRotateTransform.hxx" +#include "SGTrackToAnimation.hxx" + +#include +#include +#include + +/** + * + */ +static osg::NodePath requireNodePath( osg::Node* node, + osg::Node* haltTraversalAtNode = 0 ) +{ + const osg::NodePathList node_paths = + node->getParentalNodePaths(haltTraversalAtNode); + return node_paths.at(0); +} + +/** + * Get a subpath of an osg::NodePath + * + * @param path Path to extract subpath from + * @param start Number of elements to skip from start of #path + * + * @return Subpath starting with node at position #start + */ +static osg::NodePath subPath( const osg::NodePath& path, + size_t start ) +{ + if( start >= path.size() ) + return osg::NodePath(); + + osg::NodePath np(path.size() - start); + for(size_t i = start; i < path.size(); ++i) + np[i - start] = path[i]; + + return np; +} + +/** + * Visitor to find a group by its name. + */ +class FindGroupVisitor: + public osg::NodeVisitor +{ + public: + + FindGroupVisitor(const std::string& name): + osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), + _name(name), + _group(0) + { + if( name.empty() ) + SG_LOG(SG_IO, SG_WARN, "FindGroupVisitor: empty name provided"); + } + + osg::Group* getGroup() const + { + return _group; + } + + virtual void apply(osg::Group& group) + { + if( _name != group.getName() ) + return traverse(group); + + if( !_group ) + _group = &group; + else + SG_LOG + ( + SG_IO, + SG_WARN, + "FindGroupVisitor: name not unique '" << _name << "'" + ); + } + + protected: + + std::string _name; + osg::Group *_group; +}; + +/** + * Get angle of a triangle given by three side lengths + * + * @return Angle enclosed by @c side1 and @c side2 + */ +double angleFromSSS(double side1, double side2, double opposite) +{ + double c = ( SGMiscd::pow<2>(side1) + + SGMiscd::pow<2>(side2) + - SGMiscd::pow<2>(opposite) + ) / (2 * side1 * side2); + + if( c <= -1 ) + return M_PI; + else if( c >= 1 ) + return 0; + else + return std::acos(c); +} + +//------------------------------------------------------------------------------ +class SGTrackToAnimation::UpdateCallback: + public osg::NodeCallback +{ + public: + UpdateCallback( osg::Group* target, + const SGTrackToAnimation* anim, + osg::MatrixTransform* slave_tf ): + _target(target), + _slave_tf(slave_tf), + _root_length(0), + _slave_length(0), + _root_initial_angle(0), + _slave_dof(slave_tf ? anim->getConfig()->getIntValue("slave-dof", 1) : 0), + _condition(anim->getCondition()), + _root_disabled_value( + anim->readOffsetValue("disabled-rotation-deg") + ), + _slave_disabled_value( + anim->readOffsetValue("slave-disabled-rotation-deg") + ) + { + setName("SGTrackToAnimation::UpdateCallback"); + + _node_center = toOsg( anim->readVec3("center", "-m") ); + _slave_center = toOsg( anim->readVec3("slave-center", "-m") ); + _target_center = toOsg( anim->readVec3("target-center", "-m") ); + _lock_axis = toOsg( anim->readVec3("lock-axis") ); + _track_axis = toOsg( anim->readVec3("track-axis") ); + + if( _lock_axis.normalize() == 0.0 ) + { + anim->log(SG_WARN, "invalid lock-axis"); + _lock_axis.set(0, 1, 0); + } + + if( _slave_center != osg::Vec3() ) + { + _root_length = (_slave_center - _node_center).length(); + _slave_length = (_target_center - _slave_center).length(); + double dist = (_target_center - _node_center).length(); + + _root_initial_angle = angleFromSSS(_root_length, dist, _slave_length); + + // If no rotation should be applied to the slave element it is looking + // in the same direction then the root node. Inside the triangle given + // by the root length, slave length and distance from the root node to + // the target node, this equals an angle of 180 degrees. + _slave_initial_angle = angleFromSSS(_root_length, _slave_length, dist) + - SGMiscd::pi(); + + _track_axis = _target_center - _node_center; + } + + for(;;) + { + float proj = _lock_axis * _track_axis; + if( proj != 0.0 ) + { + anim->log(SG_WARN, "track-axis not perpendicular to lock-axis"); + + // Make tracking axis perpendicular to locked axis + _track_axis -= _lock_axis * proj; + } + + if( _track_axis.normalize() == 0.0 ) + { + anim->log(SG_WARN, "invalid track-axis"); + if( std::fabs(_lock_axis.x()) < 0.1 ) + _track_axis.set(1, 0, 0); + else + _track_axis.set(0, 1, 0); + } + else + break; + } + + _up_axis = _lock_axis ^ _track_axis; + _slave_axis2 = (_target_center - _slave_center) ^ _lock_axis; + _slave_axis2.normalize(); + + double target_offset = _lock_axis * (_target_center - _node_center); + _slave_initial_angle2 = std::asin(target_offset / _slave_length); + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + // TODO prevent invalid animation from being added? + + SGRotateTransform* tf = static_cast(node); + + // We need to wait with this initialization steps until the first update + // as this allows us to be sure all animations have already been installed + // and are therefore also accounted for calculating the animation. + if( _target ) + { + // Get path to animated node and calculated simplified paths to the + // nearest common parent node of both the animated node and the target + // node + + // start at parent to not get false results by + // also including animation transformation + osg::NodePath node_path = requireNodePath(node->getParent(0)), + target_path = requireNodePath(_target); + size_t tp_size = target_path.size(), + np_size = node_path.size(); + size_t common_parents = 0; + + for(; common_parents < std::min(tp_size, np_size); ++common_parents) + { + if( target_path[common_parents] != node_path[common_parents] ) + break; + } + + _node_path = subPath(node_path, common_parents); + _target_path = subPath(target_path, common_parents); + _target = 0; + + tf->setCenter( toSG(_node_center) ); + tf->setAxis( toSG(_lock_axis) ); + } + + double root_angle = 0, + slave_angle = 0, + slave_angle2 = 0; + + if( !_condition || _condition->test() ) + { + root_angle = -_root_initial_angle; + slave_angle = -_slave_initial_angle; + + osg::Vec3 target_pos = ( osg::computeLocalToWorld(_target_path) + * osg::computeWorldToLocal(_node_path) + ).preMult(_target_center), + dir = target_pos - _node_center; + + // Ensure direction is perpendicular to lock axis + osg::Vec3 lock_proj = _lock_axis * (_lock_axis * dir); + dir -= lock_proj; + + // Track to target + float x = dir * _track_axis, + y = dir * _up_axis; + root_angle += std::atan2(y, x); + + if( _root_length > 0 ) + { + // Handle scissor/ik rotation + double dist = dir.length(), + slave_target_dist = 0; + if( dist < _root_length + _slave_length ) + { + root_angle += angleFromSSS(_root_length, dist, _slave_length); + + if( _slave_tf ) + { + slave_angle += angleFromSSS(_root_length, _slave_length, dist) + - SGMiscd::pi(); + } + if( _slave_dof >= 2 ) + slave_target_dist = _slave_length; + } + else if( _slave_dof >= 2 ) + { + // If the distance is too large we need to manually calculate the + // distance of the slave to the target, as it is not possible + // anymore to rotate the objects to reach the target. + osg::Vec3 root_dir = target_pos - _node_center; + root_dir.normalize(); + osg::Vec3 slave_pos = _node_center + root_dir * _root_length; + slave_target_dist = (target_pos - slave_pos).length(); + } + + if( slave_target_dist > 0 ) + // Calculate angle to rotate "out of the plane" to point towards the + // target object. + slave_angle2 = std::asin( (_lock_axis * lock_proj) + / slave_target_dist ) + - _slave_initial_angle2; + } + } + else + { + root_angle = _root_disabled_value + ? SGMiscd::deg2rad(_root_disabled_value->getValue()) + : 0; + slave_angle = _slave_disabled_value + ? SGMiscd::deg2rad(_slave_disabled_value->getValue()) + : 0; + } + + tf->setAngleRad( root_angle ); + if( _slave_tf ) + { + osg::Matrix mat_tf; + SGRotateTransform::set_rotation + ( + mat_tf, + slave_angle, + SGVec3d(toSG(_slave_center)), + SGVec3d(toSG(_lock_axis)) + ); + + // Slave rotation around second axis + if( slave_angle2 != 0 ) + { + osg::Matrix mat_tf2; + SGRotateTransform::set_rotation + ( + mat_tf2, + slave_angle2, + SGVec3d(toSG(_slave_center)), + SGVec3d(toSG(_slave_axis2)) + ); + mat_tf.preMult(mat_tf2); + } + + _slave_tf->setMatrix(mat_tf); + } + + traverse(node, nv); + } + protected: + + osg::Vec3 _node_center, + _slave_center, + _target_center, + _lock_axis, + _track_axis, + _up_axis, + _slave_axis2; ///!< 2nd axis for 2dof slave + osg::Group *_target; + osg::MatrixTransform *_slave_tf; + osg::NodePath _node_path, + _target_path; + double _root_length, + _slave_length, + _root_initial_angle, + _slave_initial_angle, + _slave_initial_angle2; + int _slave_dof; + + SGSharedPtr _condition; + SGExpressiond_ref _root_disabled_value, + _slave_disabled_value; +}; + +//------------------------------------------------------------------------------ +SGTrackToAnimation::SGTrackToAnimation( osg::Node* node, + const SGPropertyNode* configNode, + SGPropertyNode* modelRoot ): + SGAnimation(configNode, modelRoot), + _target_group(0), + _slave_group(0) +{ + std::string target = configNode->getStringValue("target-name"); + FindGroupVisitor target_finder(target); + node->accept(target_finder); + + if( !(_target_group = target_finder.getGroup()) ) + log(SG_ALERT, "target not found: '" + target + '\''); + + std::string slave = configNode->getStringValue("slave-name"); + if( !slave.empty() ) + { + FindGroupVisitor slave_finder(slave); + node->accept(slave_finder); + _slave_group = slave_finder.getGroup(); + } +} + +//------------------------------------------------------------------------------ +osg::Group* SGTrackToAnimation::createAnimationGroup(osg::Group& parent) +{ + if( !_target_group ) + return 0; + + osg::MatrixTransform* slave_tf = 0; + if( _slave_group ) + { + slave_tf = new osg::MatrixTransform; + slave_tf->setName("locked-track slave animation"); + + osg::Group* parent = _slave_group->getParent(0); + slave_tf->addChild(_slave_group); + parent->removeChild(_slave_group); + parent->addChild(slave_tf); + } + + SGRotateTransform* tf = new SGRotateTransform; + tf->setName("locked-track animation"); + tf->setUpdateCallback(new UpdateCallback(_target_group, this, slave_tf)); + parent.addChild(tf); + + return tf; +} + +//------------------------------------------------------------------------------ +void SGTrackToAnimation::log(sgDebugPriority p, const std::string& msg) const +{ + SG_LOG + ( + SG_IO, + p, + // TODO handle multiple object-names? + "SGTrackToAnimation(" << getConfig()->getStringValue("object-name") << "): " + << msg + ); +} diff -Nru simgear-2.10.0/simgear/scene/model/SGTrackToAnimation.hxx simgear-3.0.0/simgear/scene/model/SGTrackToAnimation.hxx --- simgear-2.10.0/simgear/scene/model/SGTrackToAnimation.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/model/SGTrackToAnimation.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,52 @@ +// TrackTo animation +// +// http://wiki.blender.org/index.php/Doc:2.6/Manual/Constraints/Tracking/Locked_Track +// TODO: http://wiki.blender.org/index.php/Doc:2.6/Manual/Constraints/Tracking/Track_To +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_TRACK_TO_ANIMATION_HXX_ +#define SG_TRACK_TO_ANIMATION_HXX_ + +#include + +/** + * Animation to let an object always track another object. An optional second + * slave object can be specified which is rotate to always fit the space between + * the root object and the target object. This can be used to eg. create a gear + * scissor animation. + */ +class SGTrackToAnimation: + public SGAnimation +{ + public: + SGTrackToAnimation( osg::Node* node, + const SGPropertyNode* configNode, + SGPropertyNode* modelRoot ); + + virtual osg::Group* createAnimationGroup(osg::Group& parent); + + protected: + class UpdateCallback; + + osg::Group *_target_group, + *_slave_group; + + void log(sgDebugPriority p, const std::string& msg) const; +}; + +#endif /* SG_TRACK_TO_ANIMATION_HXX_ */ diff -Nru simgear-2.10.0/simgear/scene/sky/cloudfield.cxx simgear-3.0.0/simgear/scene/sky/cloudfield.cxx --- simgear-2.10.0/simgear/scene/sky/cloudfield.cxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/scene/sky/cloudfield.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -395,7 +395,7 @@ } bool SGCloudField::isDefined3D(void) { - return (cloud_hash.size() > 0); + return (! cloud_hash.empty()); } SGCloudField::CloudFog::CloudFog() { diff -Nru simgear-2.10.0/simgear/scene/sky/CloudShaderGeometry.cxx simgear-3.0.0/simgear/scene/sky/CloudShaderGeometry.cxx --- simgear-2.10.0/simgear/scene/sky/CloudShaderGeometry.cxx 2012-07-05 14:53:47.000000000 +0000 +++ simgear-3.0.0/simgear/scene/sky/CloudShaderGeometry.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -48,7 +48,7 @@ { void CloudShaderGeometry::drawImplementation(RenderInfo& renderInfo) const { - if (!_cloudsprites.size()) return; + if (_cloudsprites.empty()) return; osg::State& state = *renderInfo.getState(); diff -Nru simgear-2.10.0/simgear/scene/sky/sky.cxx simgear-3.0.0/simgear/scene/sky/sky.cxx --- simgear-2.10.0/simgear/scene/sky/sky.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/sky/sky.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -39,7 +39,6 @@ // Constructor SGSky::SGSky( void ) { effective_visibility = visibility = 10000.0; - minimum_sky_visibility = 1000; // near cloud visibility state variables in_puff = false; @@ -61,11 +60,9 @@ pre_root->setStateSet(preStateSet); cloud_root = new osg::Group; cloud_root->setNodeMask(simgear::MODEL_BIT); - - pre_selector = new osg::Switch; + cloud_root->setName("SGSky-cloud-root"); pre_transform = new osg::Group; - _ephTransform = new osg::MatrixTransform; // Set up a RNG that is repeatable within 10 minutes to ensure that clouds @@ -103,9 +100,7 @@ oursun = new SGSun; _ephTransform->addChild( oursun->build(tex_path, sun_size, property_tree_node ) ); - pre_selector->addChild( pre_transform.get() ); - - pre_root->addChild( pre_selector.get() ); + pre_root->addChild( pre_transform.get() ); } @@ -118,8 +113,6 @@ // 180 degrees = darkest midnight bool SGSky::repaint( const SGSkyColor &sc, const SGEphemeris& eph ) { - if ( effective_visibility > minimum_sky_visibility ) { - enable(); dome->repaint( sc.adj_sky_color, sc.sky_color, sc.fog_color, sc.sun_angle, effective_visibility ); @@ -133,10 +126,7 @@ cloud_layers[i]->repaint( sc.cloud_color ); } } - } else { - // turn off sky - disable(); - } + SGCloudField::updateFog((double)effective_visibility, osg::Vec4f(toOsg(sc.fog_color), 1.0f)); return true; @@ -196,6 +186,12 @@ } void +SGSky::set_visibility( float v ) +{ + visibility = std::max(v, 25.0f); +} + +void SGSky::add_cloud_layer( SGCloudLayer * layer ) { cloud_layers.push_back(layer); @@ -297,16 +293,6 @@ SGCloudField::setUseImpostors(imp); } -float SGSky::get_minimum_sky_visibility() const -{ - return minimum_sky_visibility; -} - -void SGSky::set_minimum_sky_visibility( float value ) -{ - minimum_sky_visibility = value; -} - void SGSky::texture_path( const string& path ) { tex_path = SGPath( path ); } diff -Nru simgear-2.10.0/simgear/scene/sky/sky.hxx simgear-3.0.0/simgear/scene/sky/sky.hxx --- simgear-2.10.0/simgear/scene/sky/sky.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/sky/sky.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -43,7 +43,6 @@ #include #include #include -#include #include #include @@ -224,7 +223,6 @@ layer_list_type cloud_layers; osg::ref_ptr pre_root, cloud_root; - osg::ref_ptr pre_selector; osg::ref_ptr pre_transform; osg::ref_ptr _ephTransform; @@ -234,10 +232,8 @@ // visibility float visibility; float effective_visibility; - float minimum_sky_visibility; int in_cloud; - int cur_layer_pos; // near cloud visibility state variables bool in_puff; @@ -358,19 +354,6 @@ */ void texture_path( const string& path ); - /** Enable drawing of the sky. */ - inline void enable() { - pre_selector->setValue(0, 1); - } - - /** - * Disable drawing of the sky in the scene graph. The leaf node is still - * there, how ever it won't be traversed on by ssgCullandRender() - */ - inline void disable() { - pre_selector->setValue(0, 0); - } - /** * Get the current sun color */ @@ -422,14 +405,12 @@ /** @return current effective visibility */ - inline float get_visibility() const { return effective_visibility; } + float get_visibility() const { return effective_visibility; } /** Set desired clear air visibility. * @param v visibility in meters */ - inline void set_visibility( float v ) { - effective_visibility = visibility = (v <= 25.0) ? 25.0 : v; - } + void set_visibility( float v ); /** Get 3D cloud density */ double get_3dCloudDensity() const; @@ -488,10 +469,5 @@ void set_3dCloudWrap(bool wrap); - /** Get minimum sky visibility */ - float get_minimum_sky_visibility() const; - - /** Set minimum sky visibility */ - void set_minimum_sky_visibility( float value ); }; #endif // _SG_SKY_HXX diff -Nru simgear-2.10.0/simgear/scene/tgdb/apt_signs.cxx simgear-3.0.0/simgear/scene/tgdb/apt_signs.cxx --- simgear-2.10.0/simgear/scene/tgdb/apt_signs.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/apt_signs.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -293,7 +293,7 @@ SGMaterial *material = 0; if (size < -1 || size > 5){ - SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "Found illegal sign size value of '" << size << "' for " << content << "."); + SG_LOG(SG_TERRAIN, SG_INFO, SIGN "Found illegal sign size value of '" << size << "' for " << content << "."); size = -1; } @@ -304,13 +304,13 @@ if (*s == '{') { if (cmd) - SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "Illegal taxiway sign syntax. Unexpected '{' in '" << content << "'."); + SG_LOG(SG_TERRAIN, SG_INFO, SIGN "Illegal taxiway sign syntax. Unexpected '{' in '" << content << "'."); cmd = true; continue; } else if (*s == '}') { if (!cmd) - SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "Illegal taxiway sign syntax. Unexpected '}' in '" << content << "'."); + SG_LOG(SG_TERRAIN, SG_INFO, SIGN "Illegal taxiway sign syntax. Unexpected '}' in '" << content << "'."); cmd = false; continue; @@ -328,7 +328,7 @@ } if (!*s) { - SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unclosed { in sign contents"); + SG_LOG(SG_TERRAIN, SG_INFO, SIGN "unclosed { in sign contents"); } else if (s[1] == '=') { for (s += 2; *s; s++) { value += *s; @@ -336,7 +336,7 @@ break; } if (!*s) - SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "unclosed { in sign contents"); + SG_LOG(SG_TERRAIN, SG_INFO, SIGN "unclosed { in sign contents"); } if (name == "no-entry") { @@ -377,7 +377,7 @@ if (n == "@Y") { if (size > 3) { size = -1; - SG_LOG(SG_TERRAIN, SG_ALERT, SIGN << content << " has wrong size. Allowed values are 1 to 3"); + SG_LOG(SG_TERRAIN, SG_INFO, SIGN << content << " has wrong size. Allowed values are 1 to 3"); } sign_height = HT[size < 0 ? 3 : size]; newmat = "YellowSign"; @@ -387,7 +387,7 @@ } else if (n == "@R") { if (size > 3) { size = -1; - SG_LOG(SG_TERRAIN, SG_ALERT, SIGN << content << " has wrong size. Allowed values are 1 to 3"); + SG_LOG(SG_TERRAIN, SG_INFO, SIGN << content << " has wrong size. Allowed values are 1 to 3"); } sign_height = HT[size < 0 ? 3 : size]; newmat = "RedSign"; @@ -397,7 +397,7 @@ } else if (n == "@L") { if (size > 3) { size = -1; - SG_LOG(SG_TERRAIN, SG_ALERT, SIGN << content << " has wrong size. Allowed values are 1 to 3"); + SG_LOG(SG_TERRAIN, SG_INFO, SIGN << content << " has wrong size. Allowed values are 1 to 3"); } sign_height = HT[size < 0 ? 3 : size]; newmat = "FramedSign"; @@ -407,7 +407,7 @@ } else if (n == "@B") { if ( (size != -1) && (size != 4) && (size != 5) ) { size = -1; - SG_LOG(SG_TERRAIN, SG_ALERT, SIGN << content << " has wrong size. Allowed values are 4 or 5"); + SG_LOG(SG_TERRAIN, SG_INFO, SIGN << content << " has wrong size. Allowed values are 4 or 5"); } sign_height = HT[size < 0 ? 4 : size]; newmat = "BlackSign"; @@ -424,19 +424,19 @@ } if (name[0] == '@') { - SG_LOG(SG_TERRAIN, SG_ALERT, SIGN "ignoring unknown command `" << name << '\''); + SG_LOG(SG_TERRAIN, SG_INFO, SIGN "ignoring unknown command `" << name << '\''); continue; } } - if (newmat.size()) { + if (! newmat.empty()) { material = d->materials->find(newmat); newmat.clear(); } SGMaterialGlyph *glyph = material->get_glyph(name); if (!glyph) { - SG_LOG( SG_TERRAIN, SG_ALERT, SIGN "unsupported glyph '" << *s << '\''); + SG_LOG( SG_TERRAIN, SG_INFO, SIGN "unsupported glyph '" << *s << '\''); continue; } diff -Nru simgear-2.10.0/simgear/scene/tgdb/BucketBox.hxx simgear-3.0.0/simgear/scene/tgdb/BucketBox.hxx --- simgear-2.10.0/simgear/scene/tgdb/BucketBox.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/BucketBox.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -1,6 +1,6 @@ // BucketBox.cxx -- Helper for on demand database paging. // -// Copyright (C) 2010 - 2011 Mathias Froehlich +// Copyright (C) 2010 - 2013 Mathias Froehlich // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -22,7 +22,9 @@ #include #include +#include #include +#include #include #include @@ -31,10 +33,10 @@ #define Elements(x) (sizeof(x)/sizeof((x)[0])) -// 3*5*3 * 8 = 360 -static const unsigned _lonFactors[] = { 3, 5, 3, 2, 2, 2, /* sub degree */ 2, 2, 2 }; -// 5*3*3 * 4 = 180 -static const unsigned _latFactors[] = { 5, 3, 3, 2, 2, /* sub degree */ 2, 2, 2, 1 }; +// 2*5*3*3 * 4 = 360 +static const unsigned _lonFactors[] = { 2, 5, 3, 3, 2, 2, /* sub degree */ 2, 2, 2 }; +// 3*3*5 * 4 = 180 +static const unsigned _latFactors[] = { 3, 5, 1, 3, 2, 2, /* sub degree */ 2, 2, 2 }; static unsigned product(const unsigned* factors, unsigned count) { @@ -50,13 +52,10 @@ /// bits which matches the SGBuckets maximum tile resolution. /// /// Notable /design/ decision: -/// * The longitude maps to the interval [0,360[ which appears to be -/// counter productive for the file/directory names and the -/// texture coordinates which map [-180,180[. -/// The reason is that the buckets at 89deg longitude are 8deg -/// latitude width. So there is a bunch of buckets that range from -/// [176, -184[ longitude. So the wrap happens at 0deg instead -/// of 180deg since we have a cut edge for all latitudes. +/// * The longitude maps to the interval [-180,180[. +/// The latitude maps to the interval [-90,90]. +/// This works now that the tiles do no longer cut +/// neither the 180deg nor the 0deg boundary. /// * This is not meant to be an API class for simgear. This is /// just an internal tool that I would like to keep in the SPT loader. /// But I want to have coverage somehow tested with the usual unit @@ -142,6 +141,20 @@ return SGBucket(_offsetToLongitudeDeg(offset), _offsetToLatitudeDeg(_offset[1])); } + BucketBox getParentBox(unsigned level) const + { + BucketBox box; + unsigned plon = product(_lonFactors + level, Elements(_lonFactors) - level); + unsigned plat = product(_latFactors + level, Elements(_latFactors) - level); + box._offset[0] = _offset[0] - _offset[0] % plon; + box._offset[0] = _normalizeLongitude(box._offset[0]); + box._offset[1] = _offset[1] - _offset[1] % plat; + box._size[0] = plon; + box._size[1] = plat; + + return box; + } + BucketBox getSubBoxHeight(unsigned j, unsigned level) const { assert(0 < level); @@ -197,18 +210,30 @@ SGSpheref getBoundingSphere() const { - SGSpheref sphere; - unsigned incx = 10*8; - for (unsigned i = 0; incx != 0; i += incx) { - unsigned incy = 10*8; - for (unsigned j = 0; incy != 0; j += incy) { - sphere.expandBy(SGVec3f::fromGeod(_offsetToGeod(_offset[0] + i, _offset[1] + j, -1000))); - sphere.expandBy(SGVec3f::fromGeod(_offsetToGeod(_offset[0] + i, _offset[1] + j, 10000))); + SGBoxf box; + for (unsigned i = 0, incx = 10*8; incx != 0; i += incx) { + for (unsigned j = 0, incy = 10*8; incy != 0; j += incy) { + box.expandBy(SGVec3f::fromGeod(_offsetToGeod(_offset[0] + i, _offset[1] + j, -1000))); + box.expandBy(SGVec3f::fromGeod(_offsetToGeod(_offset[0] + i, _offset[1] + j, 10000))); incy = std::min(incy, _size[1] - j); } incx = std::min(incx, _size[0] - i); } - return SGSpheref(sphere.getCenter(), sphere.getRadius() + 5000); + SGSpheref sphere(box.getCenter(), 0); + for (unsigned i = 0, incx = 10*8; incx != 0; i += incx) { + for (unsigned j = 0, incy = 10*8; incy != 0; j += incy) { + float r2; + r2 = distSqr(sphere.getCenter(), SGVec3f::fromGeod(_offsetToGeod(_offset[0] + i, _offset[1] + j, -1000))); + if (sphere.getRadius2() < r2) + sphere.setRadius(sqrt(r2)); + r2 = distSqr(sphere.getCenter(), SGVec3f::fromGeod(_offsetToGeod(_offset[0] + i, _offset[1] + j, 10000))); + if (sphere.getRadius2() < r2) + sphere.setRadius(sqrt(r2)); + incy = std::min(incy, _size[1] - j); + } + incx = std::min(incx, _size[0] - i); + } + return sphere; } // Split the current box into up to two boxes that do not cross the 360 deg border. @@ -283,22 +308,22 @@ SGGeod p00 = _offsetToGeod(x0, y0, 0); SGVec3f v00 = SGVec3f::fromGeod(p00); SGVec3f n00 = SGQuatf::fromLonLat(p00).backTransform(SGVec3f(0, 0, -1)); - SGVec2f t00(x0*1.0/(360*8) + 0.5, y0*1.0/(180*8)); + SGVec2f t00(x0*1.0/(360*8), y0*1.0/(180*8)); SGGeod p10 = _offsetToGeod(x1, y0, 0); SGVec3f v10 = SGVec3f::fromGeod(p10); SGVec3f n10 = SGQuatf::fromLonLat(p10).backTransform(SGVec3f(0, 0, -1)); - SGVec2f t10(x1*1.0/(360*8) + 0.5, y0*1.0/(180*8)); + SGVec2f t10(x1*1.0/(360*8), y0*1.0/(180*8)); SGGeod p11 = _offsetToGeod(x1, y1, 0); SGVec3f v11 = SGVec3f::fromGeod(p11); SGVec3f n11 = SGQuatf::fromLonLat(p11).backTransform(SGVec3f(0, 0, -1)); - SGVec2f t11(x1*1.0/(360*8) + 0.5, y1*1.0/(180*8)); + SGVec2f t11(x1*1.0/(360*8), y1*1.0/(180*8)); SGGeod p01 = _offsetToGeod(x0, y1, 0); SGVec3f v01 = SGVec3f::fromGeod(p01); SGVec3f n01 = SGQuatf::fromLonLat(p01).backTransform(SGVec3f(0, 0, -1)); - SGVec2f t01(x0*1.0/(360*8) + 0.5, y1*1.0/(180*8)); + SGVec2f t01(x0*1.0/(360*8), y1*1.0/(180*8)); if (y0 != 0) { points[numPoints] = v00; @@ -341,17 +366,11 @@ static unsigned _longitudeDegToOffset(double lon) { - lon = SGMiscd::normalizePeriodic(0, 360, lon); - unsigned offset = (unsigned)(8*lon + 0.5); + unsigned offset = (unsigned)(8*(lon + 180) + 0.5); return _normalizeLongitude(offset); } static double _offsetToLongitudeDeg(unsigned offset) - { - if (180*8 <= offset) - return offset*0.125 - 360; - else - return offset*0.125; - } + { return offset*0.125 - 180; } static unsigned _latitudeDegToOffset(double lat) { @@ -465,24 +484,48 @@ std::basic_ostream& operator<<(std::basic_ostream& os, const BucketBox& bucketBox) { + std::basic_stringstream ss; + + double minSize = std::min(bucketBox.getWidthDeg(), bucketBox.getHeightDeg()); + + unsigned fieldPrecision = 0; + if (minSize <= 0.125) { + fieldPrecision = 3; + } else if (minSize <= 0.25) { + fieldPrecision = 2; + } else if (minSize <= 0.5) { + fieldPrecision = 1; + } + + unsigned lonFieldWidth = 3; + if (fieldPrecision) + lonFieldWidth += 1 + fieldPrecision; + + ss << std::fixed << std::setfill('0') << std::setprecision(fieldPrecision); + double lon = bucketBox.getLongitudeDeg(); if (lon < 0) - os << "w" << -lon; + ss << "w" << std::setw(lonFieldWidth) << -lon << std::setw(0); else - os << "e" << lon; + ss << "e" << std::setw(lonFieldWidth) << lon << std::setw(0); + unsigned latFieldWidth = 2; + if (fieldPrecision) + latFieldWidth += 1 + fieldPrecision; + double lat = bucketBox.getLatitudeDeg(); if (lat < -90) lat = -90; if (90 < lat) lat = 90; if (lat < 0) - os << "s" << -lat; + ss << "s" << std::setw(latFieldWidth) << -lat << std::setw(0); else - os << "n" << lat; + ss << "n" << std::setw(latFieldWidth) << lat << std::setw(0); - os << "-" << bucketBox.getWidthDeg() << "x" << bucketBox.getHeightDeg(); - return os; + ss << "-" << bucketBox.getWidthDeg() << "x" << bucketBox.getHeightDeg(); + + return os << ss.str(); } /// Stream inout operator. diff -Nru simgear-2.10.0/simgear/scene/tgdb/CMakeLists.txt simgear-3.0.0/simgear/scene/tgdb/CMakeLists.txt --- simgear-2.10.0/simgear/scene/tgdb/CMakeLists.txt 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -41,8 +41,9 @@ simgear_scene_component(tgdb scene/tgdb "${SOURCES}" "${HEADERS}") if(ENABLE_TESTS) + add_executable(BucketBoxTest BucketBoxTest.cxx) - target_link_libraries(BucketBoxTest SimGearCore) + target_link_libraries(BucketBoxTest ${TEST_LIBS}) add_test(BucketBoxTest ${EXECUTABLE_OUTPUT_PATH}/BucketBoxTest) endif(ENABLE_TESTS) diff -Nru simgear-2.10.0/simgear/scene/tgdb/obj.cxx simgear-3.0.0/simgear/scene/tgdb/obj.cxx --- simgear-2.10.0/simgear/scene/tgdb/obj.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/obj.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -59,6 +60,7 @@ #include #include #include +#include #include "SGTexturedTriangleBin.hxx" #include "SGLightBin.hxx" @@ -77,7 +79,8 @@ typedef std::list SGLightListBin; typedef std::list SGDirectionalLightListBin; -struct SGTileGeometryBin { +class SGTileGeometryBin : public osg::Referenced { +public: SGMaterialTriangleMap materialTriangleMap; SGLightBin tileLights; SGLightBin randomTileLights; @@ -143,7 +146,7 @@ std::string materialName = obj.get_pt_materials()[grp]; SGMaterial* material = 0; if (matlib) - material = matlib->find(materialName); + material = matlib->findCached(materialName); SGVec4f color = getMaterialLightColor(material); if (3 <= materialName.size() && materialName.substr(0, 3) != "RWY") { @@ -281,7 +284,7 @@ triangles.insert(v0, v1, v2); } } - + static void addFanGeometry(SGTexturedTriangleBin& triangles, const std::vector& vertices, @@ -323,7 +326,7 @@ { if (!matlib) return SGVec2f(1, 1); - SGMaterial* material = matlib->find(name); + SGMaterial* material = matlib->findCached(name); if (!material) return SGVec2f(1, 1); @@ -397,14 +400,17 @@ osg::Geometry* geometry = i->second.buildGeometry(); SGMaterial *mat = 0; if (matlib) - mat = matlib->find(i->first); + mat = matlib->findCached(i->first); eg = new EffectGeode; + eg->setName("EffectGeode"); if (mat) eg->setEffect(mat->get_effect(i->second)); eg->addDrawable(geometry); eg->runGenerators(geometry); // Generate extra data needed by effect - if (group) + if (group) { + group->setName("surfaceGeometryGroup"); group->addChild(eg); + } } if (group) return group; @@ -415,13 +421,13 @@ void computeRandomSurfaceLights(SGMaterialLib* matlib) { SGMaterialTriangleMap::iterator i; - + // generate a repeatable random seed mt seed; mt_init(&seed, unsigned(123)); - + for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { - SGMaterial *mat = matlib->find(i->first); + SGMaterial *mat = matlib->findCached(i->first); if (!mat) continue; @@ -433,7 +439,7 @@ << coverage << ", pushing up to 10000"); coverage = 10000; } - + std::vector randomPoints; i->second.addRandomSurfacePoints(coverage, 3, mat->get_object_mask(i->second), randomPoints); std::vector::iterator j; @@ -462,50 +468,43 @@ } } } - + void computeRandomObjectsAndBuildings( - SGMaterialLib* matlib, - float building_density, - bool use_random_objects, + SGMaterialLib* matlib, + float building_density, + bool use_random_objects, bool use_random_buildings) { SGMaterialTriangleMap::iterator i; - + // generate a repeatable random seed mt seed; mt_init(&seed, unsigned(123)); - + for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { - SGMaterial *mat = matlib->find(i->first); + SGMaterial *mat = matlib->findCached(i->first); SGTexturedTriangleBin triangleBin = i->second; - + if (!mat) continue; osg::Texture2D* object_mask = mat->get_object_mask(triangleBin); + int group_count = mat->get_object_group_count(); - float building_coverage = mat->get_building_coverage(); + float building_coverage = mat->get_building_coverage(); float cos_zero_density_angle = mat->get_cos_object_zero_density_slope_angle(); float cos_max_density_angle = mat->get_cos_object_max_density_slope_angle(); - - bool found = false; + + if (building_coverage == 0) + continue; + SGBuildingBin* bin = NULL; - - if (building_coverage > 0) { - BOOST_FOREACH(bin, randomBuildings) - { - if (bin->getMaterialName() == mat->get_names()[0]) { - found = true; - break; - } - } - - if (!found) { - bin = new SGBuildingBin(mat); - randomBuildings.push_back(bin); - } - } - + + if (building_coverage > 0) { + bin = new SGBuildingBin(mat); + randomBuildings.push_back(bin); + } + unsigned num = i->second.getNumTriangles(); int random_dropped = 0; int mask_dropped = 0; @@ -514,7 +513,7 @@ for (unsigned i = 0; i < num; ++i) { SGTexturedTriangleBin::triangle_ref triangleRef = triangleBin.getTriangleRef(i); - + SGVec3f vorigin = triangleBin.getVertex(triangleRef[0]).vertex; SGVec3f v0 = triangleBin.getVertex(triangleRef[1]).vertex - vorigin; SGVec3f v1 = triangleBin.getVertex(triangleRef[2]).vertex - vorigin; @@ -522,49 +521,49 @@ SGVec2f t0 = triangleBin.getVertex(triangleRef[1]).texCoord - torigin; SGVec2f t1 = triangleBin.getVertex(triangleRef[2]).texCoord - torigin; SGVec3f normal = cross(v0, v1); - + // Ensure the slope isn't too steep by checking the // cos of the angle between the slope normal and the // vertical (conveniently the z-component of the normalized - // normal) and values passed in. + // normal) and values passed in. float cos = normalize(normal).z(); float slope_density = 1.0; if (cos < cos_zero_density_angle) continue; // Too steep for any objects if (cos < cos_max_density_angle) { - slope_density = - (cos - cos_zero_density_angle) / + slope_density = + (cos - cos_zero_density_angle) / (cos_max_density_angle - cos_zero_density_angle); } - + // Containers to hold the random buildings and objects generated // for this triangle for collision detection purposes. std::vector< std::pair< SGVec3f, float> > triangleObjectsList; std::vector< std::pair< SGVec3f, float> > triangleBuildingList; - + // Compute the area float area = 0.5f*length(normal); if (area <= SGLimitsf::min()) continue; - // Generate any random objects + // Generate any random objects if (use_random_objects && (group_count > 0)) { for (int j = 0; j < group_count; j++) { SGMatModelGroup *object_group = mat->get_object_group(j); int nObjects = object_group->get_object_count(); - + if (nObjects == 0) continue; - + // For each of the random models in the group, determine an appropriate // number of random placements and insert them. for (int k = 0; k < nObjects; k++) { SGMatModel * object = object_group->get_object(k); - + // Determine the number of objecst to place, taking into account // the slope density factor. double n = slope_density * area / object->get_coverage_m2(); - + // Use the zombie door method to determine fractional object placement. n = n + mt_rand(&seed); @@ -579,85 +578,83 @@ SGVec3f randomPoint = vorigin + a*v0 + b*v1; float rotation = static_cast(mt_rand(&seed)); - + // Check that the point is sufficiently far from // the edge of the triangle by measuring the distance - // from the three lines that make up the triangle. + // from the three lines that make up the triangle. float spacing = object->get_spacing_m(); - - SGVec3f p = randomPoint - vorigin; + + SGVec3f p = randomPoint - vorigin; float edges[] = { length(cross(p , p - v0)) / length(v0), length(cross(p - v0, p - v1)) / length(v1 - v0), length(cross(p - v1, p )) / length(v1) }; - float edge_dist = *std::min_element(edges, edges + 3); - - if (edge_dist < spacing) { + float edge_dist = *std::min_element(edges, edges + 3); + + if (edge_dist < spacing) { n -= 1.0; - continue; - } - + continue; + } + if (object_mask != NULL) { SGVec2f texCoord = torigin + a*t0 + b*t1; - + // Check this random point against the object mask - // blue (for buildings) channel. - osg::Image* img = object_mask->getImage(); + // blue (for buildings) channel. + osg::Image* img = object_mask->getImage(); unsigned int x = (int) (img->s() * texCoord.x()) % img->s(); unsigned int y = (int) (img->t() * texCoord.y()) % img->t(); - - if (mt_rand(&seed) > img->getColor(x, y).b()) { + + if (mt_rand(&seed) > img->getColor(x, y).b()) { // Failed object mask check n -= 1.0; - continue; + continue; } - + rotation = img->getColor(x,y).r(); } - + bool close = false; // Check it isn't too close to any other random objects in the triangle std::vector >::iterator l; for (l = triangleObjectsList.begin(); l != triangleObjectsList.end(); ++l) { - float min_dist2 = (l->second + object->get_spacing_m()) * + float min_dist2 = (l->second + object->get_spacing_m()) * (l->second + object->get_spacing_m()); - + if (distSqr(l->first, randomPoint) > min_dist2) { close = true; continue; } } - + if (!close) { triangleObjectsList.push_back(std::make_pair(randomPoint, object->get_spacing_m())); - randomModels.insert(randomPoint, - object, - (int)object->get_randomized_range_m(&seed), + randomModels.insert(randomPoint, + object, + (int)object->get_randomized_range_m(&seed), rotation); } - - n -= 1.0; } } } - } - + } + // Random objects now generated. Now generate the random buildings (if any); if (use_random_buildings && (building_coverage > 0) && (building_density > 0)) { - + // Calculate the number of buildings, taking into account building density (which is linear) - // and the slope density factor. + // and the slope density factor. double num = building_density * building_density * slope_density * area / building_coverage; - + // For partial units of area, use a zombie door method to // create the proper random chance of an object being created // for this triangle. num = num + mt_rand(&seed); if (num < 1.0f) { - continue; + continue; } - + // Cosine of the angle between the two vectors. float cosine = (dot(v0, v1) / (length(v0) * length(v1))); @@ -665,137 +662,133 @@ // coverage will result. float stepv0 = (sqrtf(building_coverage) / building_density) / length(v0) / sqrtf(1 - cosine * cosine); float stepv1 = (sqrtf(building_coverage) / building_density) / length(v1); - + stepv0 = std::min(stepv0, 1.0f); stepv1 = std::min(stepv1, 1.0f); - + // Start at a random point. a will be immediately incremented below. - float a = -mt_rand(&seed) * stepv0; + float a = -mt_rand(&seed) * stepv0; float b = mt_rand(&seed) * stepv1; // Place an object each unit of area while (num > 1.0) { + num -= 1.0; - // Set the next location to place a building + // Set the next location to place a building a += stepv0; - + if ((a + b) > 1.0f) { // Reached the end of the scan-line on v0. Reset and increment // scan-line on v1 a = mt_rand(&seed) * stepv0; b += stepv1; } - + if (b > 1.0f) { - // In a degenerate case of a single point, we might be outside the + // In a degenerate case of a single point, we might be outside the // scanline. Note that we need to still ensure that a+b < 1. b = mt_rand(&seed) * stepv1 * (1.0f - a); } - + if ((a + b) > 1.0f ) { // Truly degenerate case - simply choose a random point guaranteed // to fulfil the constraing of a+b < 1. a = mt_rand(&seed); b = mt_rand(&seed) * (1.0f - a); } - + SGVec3f randomPoint = vorigin + a*v0 + b*v1; float rotation = mt_rand(&seed); - + if (object_mask != NULL) { SGVec2f texCoord = torigin + a*t0 + b*t1; - osg::Image* img = object_mask->getImage(); + osg::Image* img = object_mask->getImage(); int x = (int) (img->s() * texCoord.x()) % img->s(); int y = (int) (img->t() * texCoord.y()) % img->t(); - + // In some degenerate cases x or y can be < 1, in which case the mod operand fails while (x < 0) x += img->s(); while (y < 0) y += img->t(); - if (mt_rand(&seed) < img->getColor(x, y).b()) { + if (mt_rand(&seed) < img->getColor(x, y).b()) { // Object passes mask. Rotation is taken from the red channel rotation = img->getColor(x,y).r(); } else { // Fails mask test - try again. mask_dropped++; - num -= 1.0; continue; - } + } } // Check building isn't too close to the triangle edge. float type_roll = mt_rand(&seed); SGBuildingBin::BuildingType buildingtype = bin->getBuildingType(type_roll); float radius = bin->getBuildingMaxRadius(buildingtype); - - // Determine the actual center of the building, by shifting from the + + // Determine the actual center of the building, by shifting from the // center of the front face to the true center. osg::Matrix rotationMat = osg::Matrix::rotate(- rotation * M_PI * 2, osg::Vec3f(0.0, 0.0, 1.0)); SGVec3f buildingCenter = randomPoint + toSG(osg::Vec3f(-0.5 * bin->getBuildingMaxDepth(buildingtype), 0.0, 0.0) * rotationMat); - SGVec3f p = buildingCenter - vorigin; + SGVec3f p = buildingCenter - vorigin; float edges[] = { length(cross(p , p - v0)) / length(v0), length(cross(p - v0, p - v1)) / length(v1 - v0), length(cross(p - v1, p )) / length(v1) }; - float edge_dist = *std::min_element(edges, edges + 3); - - if (edge_dist < radius) { - num -= 1.0; + float edge_dist = *std::min_element(edges, edges + 3); + + if (edge_dist < radius) { triangle_dropped++; - continue; + continue; } - - // Check building isn't too close to random objects and other buildings. + + // Check building isn't too close to random objects and other buildings. bool close = false; std::vector >::iterator iter; - + for (iter = triangleBuildingList.begin(); iter != triangleBuildingList.end(); ++iter) { float min_dist = iter->second + radius; if (distSqr(iter->first, buildingCenter) < min_dist * min_dist) { close = true; continue; - } + } } - + if (close) { - num -= 1.0; building_dropped++; - continue; + continue; } - + for (iter = triangleObjectsList.begin(); iter != triangleObjectsList.end(); ++iter) { float min_dist = iter->second + radius; if (distSqr(iter->first, buildingCenter) < min_dist * min_dist) { close = true; continue; - } + } } - + if (close) { - num -= 1.0; random_dropped++; - continue; - } + continue; + } - std::pair pt = std::make_pair(buildingCenter, radius); + std::pair pt = std::make_pair(buildingCenter, radius); triangleBuildingList.push_back(pt); bin->insert(randomPoint, rotation, buildingtype); - num -= 1.0; } } - + triangleObjectsList.clear(); - triangleBuildingList.clear(); + triangleBuildingList.clear(); } - + SG_LOG(SG_TERRAIN, SG_DEBUG, "Random Buildings: " << ((bin) ? bin->getNumBuildings() : 0)); SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to mask: " << mask_dropped); SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to random object: " << random_dropped); SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to other buildings: " << building_dropped); } } - + void computeRandomForest(SGMaterialLib* matlib, float vegetation_density) { SGMaterialTriangleMap::iterator i; @@ -806,18 +799,18 @@ mt_init(&seed, unsigned(586)); for (i = materialTriangleMap.begin(); i != materialTriangleMap.end(); ++i) { - SGMaterial *mat = matlib->find(i->first); + SGMaterial *mat = matlib->findCached(i->first); if (!mat) continue; float wood_coverage = mat->get_wood_coverage(); if ((wood_coverage <= 0) || (vegetation_density <= 0)) continue; - + // Attributes that don't vary by tree but do vary by material bool found = false; TreeBin* bin = NULL; - + BOOST_FOREACH(bin, randomForest) { if ((bin->texture == mat->get_tree_texture() ) && @@ -829,7 +822,7 @@ break; } } - + if (!found) { bin = new TreeBin(); bin->texture = mat->get_tree_texture(); @@ -848,7 +841,7 @@ mat->get_cos_tree_max_density_slope_angle(), mat->get_cos_tree_zero_density_slope_angle(), randomPoints); - + std::vector::iterator k; for (k = randomPoints.begin(); k != randomPoints.end(); ++k) { bin->insert(*k); @@ -889,291 +882,366 @@ typedef QuadTreeBuilder RandomObjectsQuadtree; -osg::Node* -SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options) -{ - SGBinObject tile; - if (!tile.read_bin(path)) - return NULL; - - SGMaterialLib* matlib = 0; - bool use_random_objects = false; - bool use_random_vegetation = false; - bool use_random_buildings = false; - float vegetation_density = 1.0f; - float building_density = 1.0f; - if (options) { - matlib = options->getMaterialLib(); - SGPropertyNode* propertyNode = options->getPropertyNode().get(); - if (propertyNode) { - use_random_objects - = propertyNode->getBoolValue("/sim/rendering/random-objects", - use_random_objects); - use_random_vegetation - = propertyNode->getBoolValue("/sim/rendering/random-vegetation", - use_random_vegetation); - vegetation_density - = propertyNode->getFloatValue("/sim/rendering/vegetation-density", - vegetation_density); - use_random_buildings - = propertyNode->getBoolValue("/sim/rendering/random-buildings", - use_random_buildings); - building_density - = propertyNode->getFloatValue("/sim/rendering/building-density", - building_density); +class RandomObjectCallback : public OptionsReadFileCallback { +public: + virtual osgDB::ReaderWriter::ReadResult + readNode(const std::string&, const osgDB::Options*) + { + osg::ref_ptr group = new osg::Group; + group->setName("Random Object and Lighting Group"); + group->setDataVariance(osg::Object::STATIC); + + osg::LOD* lightLOD = generateLightingTileObjects(); + if (lightLOD) + group->addChild(lightLOD); + + osg::LOD* objectLOD = generateRandomTileObjects(); + if (objectLOD) + group->addChild(objectLOD); + + return group.release(); } - } - SGVec3d center = tile.get_gbs_center(); - SGGeod geodPos = SGGeod::fromCart(center); - SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180); - - // rotate the tiles so that the bounding boxes get nearly axis aligned. - // this will help the collision tree's bounding boxes a bit ... - std::vector nodes = tile.get_wgs84_nodes(); - for (unsigned i = 0; i < nodes.size(); ++i) - nodes[i] = hlOr.transform(nodes[i]); - tile.set_wgs84_nodes(nodes); - - SGQuatf hlOrf(hlOr[0], hlOr[1], hlOr[2], hlOr[3]); - std::vector normals = tile.get_normals(); - for (unsigned i = 0; i < normals.size(); ++i) - normals[i] = hlOrf.transform(normals[i]); - tile.set_normals(normals); - - SGTileGeometryBin tileGeometryBin; - if (!tileGeometryBin.insertBinObj(tile, matlib)) - return NULL; - - SGVec3f up(0, 0, 1); - GroundLightManager* lightManager = GroundLightManager::instance(); - - osg::ref_ptr lightGroup = new SGOffsetTransform(0.94); - osg::ref_ptr randomObjects; - osg::ref_ptr forestNode; - osg::ref_ptr buildingNode; - osg::Group* terrainGroup = new osg::Group; - - osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib); - if (node) - terrainGroup->addChild(node); - - if (matlib && (use_random_objects || use_random_buildings)) { - tileGeometryBin.computeRandomObjectsAndBuildings(matlib, - building_density, - use_random_objects, - use_random_buildings); - } + // Generate all the lighting objects for the tile. + osg::LOD* generateLightingTileObjects() + { + SGMaterialLibPtr matlib; - if (tileGeometryBin.randomModels.getNumModels() > 0) { - // Generate a repeatable random seed - mt seed; - mt_init(&seed, unsigned(123)); + if (_options) + matlib = _options->getMaterialLib(); - std::vector models; - for (unsigned int i = 0; - i < tileGeometryBin.randomModels.getNumModels(); i++) { - SGMatModelBin::MatModel obj - = tileGeometryBin.randomModels.getMatModel(i); - - SGPropertyNode* root = options->getPropertyNode()->getRootNode(); - osg::Node* node = obj.model->get_random_model(root, &seed); - - // Create a matrix to place the object in the correct - // location, and then apply the rotation matrix created - // above, with an additional random (or taken from - // the object mask) heading rotation if appropriate. - osg::Matrix transformMat; - transformMat = osg::Matrix::translate(toOsg(obj.position)); - if (obj.model->get_heading_type() == SGMatModel::HEADING_RANDOM) { - // Rotate the object around the z axis. - double hdg = mt_rand(&seed) * M_PI * 2; - transformMat.preMult(osg::Matrix::rotate(hdg, - osg::Vec3d(0.0, 0.0, 1.0))); - } - - if (obj.model->get_heading_type() == SGMatModel::HEADING_MASK) { - // Rotate the object around the z axis. - double hdg = - obj.rotation * M_PI * 2; - transformMat.preMult(osg::Matrix::rotate(hdg, - osg::Vec3d(0.0, 0.0, 1.0))); - } - - osg::MatrixTransform* position = - new osg::MatrixTransform(transformMat); - position->addChild(node); - models.push_back(ModelLOD(position, obj.lod)); - } - RandomObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD())); - quadtree.buildQuadTree(models.begin(), models.end()); - randomObjects = quadtree.getRoot(); - randomObjects->setName("Random objects"); - } + // FIXME: ugly, has a side effect + if (matlib) + _tileGeometryBin->computeRandomSurfaceLights(matlib); - if (tileGeometryBin.randomBuildings.size() > 0) { - buildingNode = createRandomBuildings(tileGeometryBin.randomBuildings, osg::Matrix::identity(), - options); - buildingNode->setName("Random buildings"); - } + GroundLightManager* lightManager = GroundLightManager::instance(); + osg::ref_ptr lightGroup = new SGOffsetTransform(0.94); + SGVec3f up(0, 0, 1); + + if (_tileGeometryBin->tileLights.getNumLights() > 0 + || _tileGeometryBin->randomTileLights.getNumLights() > 0) { + osg::Group* groundLights0 = new osg::Group; + groundLights0->setStateSet(lightManager->getGroundLightStateSet()); + groundLights0->setNodeMask(GROUNDLIGHTS0_BIT); + osg::Geode* geode = new osg::Geode; + geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->tileLights)); + geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->randomTileLights, 4, -0.3f)); + groundLights0->addChild(geode); + lightGroup->addChild(groundLights0); + } - if (use_random_vegetation && matlib) { - // Now add some random forest. - tileGeometryBin.computeRandomForest(matlib, vegetation_density); - - if (tileGeometryBin.randomForest.size() > 0) { - forestNode = createForest(tileGeometryBin.randomForest, osg::Matrix::identity(), - options); - forestNode->setName("Random trees"); - } - } - - // FIXME: ugly, has a side effect - if (matlib) - tileGeometryBin.computeRandomSurfaceLights(matlib); - - if (tileGeometryBin.tileLights.getNumLights() > 0 - || tileGeometryBin.randomTileLights.getNumLights() > 0) { - osg::Group* groundLights0 = new osg::Group; - groundLights0->setStateSet(lightManager->getGroundLightStateSet()); - groundLights0->setNodeMask(GROUNDLIGHTS0_BIT); - osg::Geode* geode = new osg::Geode; - geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.tileLights)); - geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 4, -0.3f)); - groundLights0->addChild(geode); - lightGroup->addChild(groundLights0); - } - - if (tileGeometryBin.randomTileLights.getNumLights() > 0) { - osg::Group* groundLights1 = new osg::Group; - groundLights1->setStateSet(lightManager->getGroundLightStateSet()); - groundLights1->setNodeMask(GROUNDLIGHTS1_BIT); - osg::Group* groundLights2 = new osg::Group; - groundLights2->setStateSet(lightManager->getGroundLightStateSet()); - groundLights2->setNodeMask(GROUNDLIGHTS2_BIT); - osg::Geode* geode = new osg::Geode; - geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 2, -0.15f)); - groundLights1->addChild(geode); - lightGroup->addChild(groundLights1); - geode = new osg::Geode; - geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights)); - groundLights2->addChild(geode); - lightGroup->addChild(groundLights2); - } + if (_tileGeometryBin->randomTileLights.getNumLights() > 0) { + osg::Group* groundLights1 = new osg::Group; + groundLights1->setStateSet(lightManager->getGroundLightStateSet()); + groundLights1->setNodeMask(GROUNDLIGHTS1_BIT); + osg::Group* groundLights2 = new osg::Group; + groundLights2->setStateSet(lightManager->getGroundLightStateSet()); + groundLights2->setNodeMask(GROUNDLIGHTS2_BIT); + osg::Geode* geode = new osg::Geode; + geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->randomTileLights, 2, -0.15f)); + groundLights1->addChild(geode); + lightGroup->addChild(groundLights1); + geode = new osg::Geode; + geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->randomTileLights)); + groundLights2->addChild(geode); + lightGroup->addChild(groundLights2); + } + + if (!_tileGeometryBin->vasiLights.empty()) { + EffectGeode* vasiGeode = new EffectGeode; + Effect* vasiEffect + = getLightEffect(24, osg::Vec3(1, 0.0001, 0.000001), 1, 24, true); + vasiGeode->setEffect(vasiEffect); + SGVec4f red(1, 0, 0, 1); + SGMaterial* mat = 0; + if (matlib) + mat = matlib->findCached("RWY_RED_LIGHTS"); + if (mat) + red = mat->get_light_color(); + SGVec4f white(1, 1, 1, 1); + mat = 0; + if (matlib) + mat = matlib->findCached("RWY_WHITE_LIGHTS"); + if (mat) + white = mat->get_light_color(); + SGDirectionalLightListBin::const_iterator i; + for (i = _tileGeometryBin->vasiLights.begin(); + i != _tileGeometryBin->vasiLights.end(); ++i) { + vasiGeode->addDrawable(SGLightFactory::getVasi(up, *i, red, white)); + } + vasiGeode->setStateSet(lightManager->getRunwayLightStateSet()); + lightGroup->addChild(vasiGeode); + } + + Effect* runwayEffect = 0; + if (_tileGeometryBin->runwayLights.getNumLights() > 0 + || !_tileGeometryBin->rabitLights.empty() + || !_tileGeometryBin->reilLights.empty() + || !_tileGeometryBin->odalLights.empty() + || _tileGeometryBin->taxiLights.getNumLights() > 0) + runwayEffect = getLightEffect(16, osg::Vec3(1, 0.001, 0.0002), 1, 16, true); + if (_tileGeometryBin->runwayLights.getNumLights() > 0 + || !_tileGeometryBin->rabitLights.empty() + || !_tileGeometryBin->reilLights.empty() + || !_tileGeometryBin->odalLights.empty() + || !_tileGeometryBin->holdshortLights.empty() + || !_tileGeometryBin->guardLights.empty()) { + osg::Group* rwyLights = new osg::Group; + rwyLights->setStateSet(lightManager->getRunwayLightStateSet()); + rwyLights->setNodeMask(RUNWAYLIGHTS_BIT); + if (_tileGeometryBin->runwayLights.getNumLights() != 0) { + EffectGeode* geode = new EffectGeode; + geode->setEffect(runwayEffect); + geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->runwayLights)); + rwyLights->addChild(geode); + } + SGDirectionalLightListBin::const_iterator i; + for (i = _tileGeometryBin->rabitLights.begin(); + i != _tileGeometryBin->rabitLights.end(); ++i) { + rwyLights->addChild(SGLightFactory::getSequenced(*i)); + } + for (i = _tileGeometryBin->reilLights.begin(); + i != _tileGeometryBin->reilLights.end(); ++i) { + rwyLights->addChild(SGLightFactory::getSequenced(*i)); + } + for (i = _tileGeometryBin->holdshortLights.begin(); + i != _tileGeometryBin->holdshortLights.end(); ++i) { + rwyLights->addChild(SGLightFactory::getHoldShort(*i)); + } + for (i = _tileGeometryBin->guardLights.begin(); + i != _tileGeometryBin->guardLights.end(); ++i) { + rwyLights->addChild(SGLightFactory::getGuard(*i)); + } + SGLightListBin::const_iterator j; + for (j = _tileGeometryBin->odalLights.begin(); + j != _tileGeometryBin->odalLights.end(); ++j) { + rwyLights->addChild(SGLightFactory::getOdal(*j)); + } + lightGroup->addChild(rwyLights); + } + + if (_tileGeometryBin->taxiLights.getNumLights() > 0) { + osg::Group* taxiLights = new osg::Group; + taxiLights->setStateSet(lightManager->getTaxiLightStateSet()); + taxiLights->setNodeMask(RUNWAYLIGHTS_BIT); + EffectGeode* geode = new EffectGeode; + geode->setEffect(runwayEffect); + geode->addDrawable(SGLightFactory::getLights(_tileGeometryBin->taxiLights)); + taxiLights->addChild(geode); + lightGroup->addChild(taxiLights); + } - if (!tileGeometryBin.vasiLights.empty()) { - EffectGeode* vasiGeode = new EffectGeode; - Effect* vasiEffect - = getLightEffect(24, osg::Vec3(1, 0.0001, 0.000001), 1, 24, true); - vasiGeode->setEffect(vasiEffect); - SGVec4f red(1, 0, 0, 1); - SGMaterial* mat = 0; - if (matlib) - mat = matlib->find("RWY_RED_LIGHTS"); - if (mat) - red = mat->get_light_color(); - SGVec4f white(1, 1, 1, 1); - mat = 0; - if (matlib) - mat = matlib->find("RWY_WHITE_LIGHTS"); - if (mat) - white = mat->get_light_color(); - SGDirectionalLightListBin::const_iterator i; - for (i = tileGeometryBin.vasiLights.begin(); - i != tileGeometryBin.vasiLights.end(); ++i) { - vasiGeode->addDrawable(SGLightFactory::getVasi(up, *i, red, white)); + osg::LOD* lightLOD = NULL; + + if (lightGroup->getNumChildren() > 0) { + lightLOD = new osg::LOD; + lightLOD->addChild(lightGroup.get(), 0, 60000); + // VASI is always on, so doesn't use light bits. + lightLOD->setNodeMask(LIGHTS_BITS | MODEL_BIT | PERMANENTLIGHT_BIT); + } + + return lightLOD; } - vasiGeode->setStateSet(lightManager->getRunwayLightStateSet()); - lightGroup->addChild(vasiGeode); - } - - Effect* runwayEffect = 0; - if (tileGeometryBin.runwayLights.getNumLights() > 0 - || !tileGeometryBin.rabitLights.empty() - || !tileGeometryBin.reilLights.empty() - || !tileGeometryBin.odalLights.empty() - || tileGeometryBin.taxiLights.getNumLights() > 0) - runwayEffect = getLightEffect(16, osg::Vec3(1, 0.001, 0.0002), 1, 16, true); - if (tileGeometryBin.runwayLights.getNumLights() > 0 - || !tileGeometryBin.rabitLights.empty() - || !tileGeometryBin.reilLights.empty() - || !tileGeometryBin.odalLights.empty() - || !tileGeometryBin.holdshortLights.empty() - || !tileGeometryBin.guardLights.empty()) { - osg::Group* rwyLights = new osg::Group; - rwyLights->setStateSet(lightManager->getRunwayLightStateSet()); - rwyLights->setNodeMask(RUNWAYLIGHTS_BIT); - if (tileGeometryBin.runwayLights.getNumLights() != 0) { - EffectGeode* geode = new EffectGeode; - geode->setEffect(runwayEffect); - geode->addDrawable(SGLightFactory::getLights(tileGeometryBin - .runwayLights)); - rwyLights->addChild(geode); - } - SGDirectionalLightListBin::const_iterator i; - for (i = tileGeometryBin.rabitLights.begin(); - i != tileGeometryBin.rabitLights.end(); ++i) { - rwyLights->addChild(SGLightFactory::getSequenced(*i)); - } - for (i = tileGeometryBin.reilLights.begin(); - i != tileGeometryBin.reilLights.end(); ++i) { - rwyLights->addChild(SGLightFactory::getSequenced(*i)); - } - for (i = tileGeometryBin.holdshortLights.begin(); - i != tileGeometryBin.holdshortLights.end(); ++i) { - rwyLights->addChild(SGLightFactory::getHoldShort(*i)); - } - for (i = tileGeometryBin.guardLights.begin(); - i != tileGeometryBin.guardLights.end(); ++i) { - rwyLights->addChild(SGLightFactory::getGuard(*i)); - } - SGLightListBin::const_iterator j; - for (j = tileGeometryBin.odalLights.begin(); - j != tileGeometryBin.odalLights.end(); ++j) { - rwyLights->addChild(SGLightFactory::getOdal(*j)); + + // Generate all the random forest, objects and buildings for the tile + osg::LOD* generateRandomTileObjects() + { + SGMaterialLibPtr matlib; + bool use_random_objects = false; + bool use_random_vegetation = false; + bool use_random_buildings = false; + float vegetation_density = 1.0f; + float building_density = 1.0f; + + osg::ref_ptr randomObjects; + osg::ref_ptr forestNode; + osg::ref_ptr buildingNode; + + if (_options) { + matlib = _options->getMaterialLib(); + SGPropertyNode* propertyNode = _options->getPropertyNode().get(); + if (propertyNode) { + use_random_objects + = propertyNode->getBoolValue("/sim/rendering/random-objects", + use_random_objects); + use_random_vegetation + = propertyNode->getBoolValue("/sim/rendering/random-vegetation", + use_random_vegetation); + vegetation_density + = propertyNode->getFloatValue("/sim/rendering/vegetation-density", + vegetation_density); + use_random_buildings + = propertyNode->getBoolValue("/sim/rendering/random-buildings", + use_random_buildings); + building_density + = propertyNode->getFloatValue("/sim/rendering/building-density", + building_density); + } + } + + + + if (matlib && (use_random_objects || use_random_buildings)) { + _tileGeometryBin->computeRandomObjectsAndBuildings(matlib, + building_density, + use_random_objects, + use_random_buildings); + } + + + if (_tileGeometryBin->randomModels.getNumModels() > 0) { + // Generate a repeatable random seed + mt seed; + mt_init(&seed, unsigned(123)); + + std::vector models; + for (unsigned int i = 0; + i < _tileGeometryBin->randomModels.getNumModels(); i++) { + SGMatModelBin::MatModel obj + = _tileGeometryBin->randomModels.getMatModel(i); + + SGPropertyNode* root = _options->getPropertyNode()->getRootNode(); + osg::Node* node = obj.model->get_random_model(root, &seed); + + // Create a matrix to place the object in the correct + // location, and then apply the rotation matrix created + // above, with an additional random (or taken from + // the object mask) heading rotation if appropriate. + osg::Matrix transformMat; + transformMat = osg::Matrix::translate(toOsg(obj.position)); + if (obj.model->get_heading_type() == SGMatModel::HEADING_RANDOM) { + // Rotate the object around the z axis. + double hdg = mt_rand(&seed) * M_PI * 2; + transformMat.preMult(osg::Matrix::rotate(hdg, + osg::Vec3d(0.0, 0.0, 1.0))); + } + + if (obj.model->get_heading_type() == SGMatModel::HEADING_MASK) { + // Rotate the object around the z axis. + double hdg = - obj.rotation * M_PI * 2; + transformMat.preMult(osg::Matrix::rotate(hdg, + osg::Vec3d(0.0, 0.0, 1.0))); + } + + osg::MatrixTransform* position = + new osg::MatrixTransform(transformMat); + position->setName("positionRandomModel"); + position->addChild(node); + models.push_back(ModelLOD(position, obj.lod)); + } + RandomObjectsQuadtree quadtree((GetModelLODCoord()), (AddModelLOD())); + quadtree.buildQuadTree(models.begin(), models.end()); + randomObjects = quadtree.getRoot(); + randomObjects->setName("Random objects"); + } + + if (! _tileGeometryBin->randomBuildings.empty()) { + buildingNode = createRandomBuildings(_tileGeometryBin->randomBuildings, osg::Matrix::identity(), + _options); + buildingNode->setName("Random buildings"); + _tileGeometryBin->randomBuildings.clear(); + } + + if (use_random_vegetation && matlib) { + // Now add some random forest. + _tileGeometryBin->computeRandomForest(matlib, vegetation_density); + + if (! _tileGeometryBin->randomForest.empty()) { + forestNode = createForest(_tileGeometryBin->randomForest, osg::Matrix::identity(), + _options); + forestNode->setName("Random trees"); + } + } + + osg::LOD* objectLOD = NULL; + + if (randomObjects.valid() || forestNode.valid() || buildingNode.valid()) { + objectLOD = new osg::LOD; + + if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000); + if (forestNode.valid()) objectLOD->addChild(forestNode.get(), 0, 20000); + if (buildingNode.valid()) objectLOD->addChild(buildingNode.get(), 0, 20000); + + unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECEIVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT; + objectLOD->setNodeMask(nodeMask); + } + + return objectLOD; } - lightGroup->addChild(rwyLights); - } - if (tileGeometryBin.taxiLights.getNumLights() > 0) { - osg::Group* taxiLights = new osg::Group; - taxiLights->setStateSet(lightManager->getTaxiLightStateSet()); - taxiLights->setNodeMask(RUNWAYLIGHTS_BIT); - EffectGeode* geode = new EffectGeode; - geode->setEffect(runwayEffect); - geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.taxiLights)); - taxiLights->addChild(geode); - lightGroup->addChild(taxiLights); - } + /// The original options to use for this bunch of models + osg::ref_ptr _options; + osg::ref_ptr _tileGeometryBin; +}; - // The toplevel transform for that tile. - osg::MatrixTransform* transform = new osg::MatrixTransform; - transform->setName(path); - transform->setMatrix(osg::Matrix::rotate(toOsg(hlOr))* - osg::Matrix::translate(toOsg(center))); - transform->addChild(terrainGroup); - if (lightGroup->getNumChildren() > 0) { - osg::LOD* lightLOD = new osg::LOD; - lightLOD->addChild(lightGroup.get(), 0, 60000); - // VASI is always on, so doesn't use light bits. - lightLOD->setNodeMask(LIGHTS_BITS | MODEL_BIT | PERMANENTLIGHT_BIT); - transform->addChild(lightLOD); - } - - if (randomObjects.valid() || forestNode.valid() || buildingNode.valid()) { - - // Add a LoD node, so we don't try to display anything when the tile center - // is more than 20km away. - osg::LOD* objectLOD = new osg::LOD; - - if (randomObjects.valid()) objectLOD->addChild(randomObjects.get(), 0, 20000); - if (forestNode.valid()) objectLOD->addChild(forestNode.get(), 0, 20000); - if (buildingNode.valid()) objectLOD->addChild(buildingNode.get(), 0, 20000); - - unsigned nodeMask = SG_NODEMASK_CASTSHADOW_BIT | SG_NODEMASK_RECEIVESHADOW_BIT | SG_NODEMASK_TERRAIN_BIT; - objectLOD->setNodeMask(nodeMask); - transform->addChild(objectLOD); - } - transform->setNodeMask( ~simgear::MODELLIGHT_BIT ); - - return transform; +osg::Node* +SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options) +{ + SGBinObject tile; + if (!tile.read_bin(path)) + return NULL; + + SGMaterialLibPtr matlib; + + if (options) { + matlib = options->getMaterialLib(); + } + + SGVec3d center = tile.get_gbs_center(); + SGGeod geodPos = SGGeod::fromCart(center); + SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180); + + // rotate the tiles so that the bounding boxes get nearly axis aligned. + // this will help the collision tree's bounding boxes a bit ... + std::vector nodes = tile.get_wgs84_nodes(); + for (unsigned i = 0; i < nodes.size(); ++i) + nodes[i] = hlOr.transform(nodes[i]); + tile.set_wgs84_nodes(nodes); + + SGQuatf hlOrf(hlOr[0], hlOr[1], hlOr[2], hlOr[3]); + std::vector normals = tile.get_normals(); + for (unsigned i = 0; i < normals.size(); ++i) + normals[i] = hlOrf.transform(normals[i]); + tile.set_normals(normals); + + osg::ref_ptr tileGeometryBin = new SGTileGeometryBin; + + if (!tileGeometryBin->insertBinObj(tile, matlib)) + return NULL; + + osg::Group* terrainGroup = new osg::Group; + terrainGroup->setName("BTGTerrainGroup"); + + osg::Node* node = tileGeometryBin->getSurfaceGeometry(matlib); + if (node) + terrainGroup->addChild(node); + + // The toplevel transform for that tile. + osg::MatrixTransform* transform = new osg::MatrixTransform; + transform->setName(path); + transform->setMatrix(osg::Matrix::rotate(toOsg(hlOr))* + osg::Matrix::translate(toOsg(center))); + transform->addChild(terrainGroup); + + // PagedLOD for the random objects so we don't need to generate + // them all on tile loading. + osg::PagedLOD* pagedLOD = new osg::PagedLOD; + pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER); + pagedLOD->setName("pagedObjectLOD"); + + // we just need to know about the read file callback that itself holds the data + osg::ref_ptr randomObjectCallback = new RandomObjectCallback; + randomObjectCallback->_options = SGReaderWriterOptions::copyOrCreate(options); + randomObjectCallback->_tileGeometryBin = tileGeometryBin; + + osg::ref_ptr callbackOptions = new osgDB::Options; + callbackOptions->setReadFileCallback(randomObjectCallback.get()); + pagedLOD->setDatabaseOptions(callbackOptions.get()); + + pagedLOD->setFileName(pagedLOD->getNumChildren(), "Dummy name - use the stored data in the read file callback"); + pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 35000); + transform->addChild(pagedLOD); + transform->setNodeMask( ~simgear::MODELLIGHT_BIT ); + + return transform; } diff -Nru simgear-2.10.0/simgear/scene/tgdb/pt_lights.cxx simgear-3.0.0/simgear/scene/tgdb/pt_lights.cxx --- simgear-2.10.0/simgear/scene/tgdb/pt_lights.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/pt_lights.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -254,6 +254,7 @@ colors->push_back(toOsg(light.color)); osg::Geometry* geometry = new osg::Geometry; + geometry->setDataVariance(osg::Object::STATIC); geometry->setVertexArray(vertices); geometry->setNormalBinding(osg::Geometry::BIND_OFF); geometry->setColorArray(colors); @@ -291,6 +292,7 @@ colors->push_back(toOsg(invisibleColor)); osg::Geometry* geometry = new osg::Geometry; + geometry->setDataVariance(osg::Object::STATIC); geometry->setVertexArray(vertices); geometry->setNormalBinding(osg::Geometry::BIND_OFF); geometry->setColorArray(colors); @@ -327,7 +329,7 @@ } osg::Geometry* geometry = new osg::Geometry; - + geometry->setDataVariance(osg::Object::STATIC); geometry->setVertexArray(vertices); geometry->setNormalBinding(osg::Geometry::BIND_OFF); geometry->setColorArray(colors); @@ -380,7 +382,7 @@ } osg::Geometry* geometry = new osg::Geometry; - + geometry->setDataVariance(osg::Object::STATIC); geometry->setVertexArray(vertices); geometry->setNormalBinding(osg::Geometry::BIND_OFF); geometry->setColorArray(colors); diff -Nru simgear-2.10.0/simgear/scene/tgdb/ReaderWriterSPT.cxx simgear-3.0.0/simgear/scene/tgdb/ReaderWriterSPT.cxx --- simgear-2.10.0/simgear/scene/tgdb/ReaderWriterSPT.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/ReaderWriterSPT.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -1,6 +1,6 @@ // ReaderWriterSPT.cxx -- Provide a paged database for flightgear scenery. // -// Copyright (C) 2010 - 2011 Mathias Froehlich +// Copyright (C) 2010 - 2013 Mathias Froehlich // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -27,9 +27,11 @@ #include #include +#include #include #include +#include #include #include @@ -109,6 +111,68 @@ } }; +struct ReaderWriterSPT::LocalOptions { + LocalOptions(const osgDB::Options* options) : + _options(options) + { + std::string pageLevelsString; + if (_options) + pageLevelsString = _options->getPluginStringData("SimGear::SPT_PAGE_LEVELS"); + + // Get the default if nothing given from outside + if (pageLevelsString.empty()) { + // We want an other level of indirection for paging + // Here we get about 12x12 deg tiles + _pageLevels.push_back(3); + // We want an other level of indirection for paging + // Here we get about 2x2 deg tiles + _pageLevels.push_back(5); + // We want an other level of indirection for paging + // Here we get about 0.5x0.5 deg tiles + _pageLevels.push_back(7); + } else { + // If configured from outside + std::stringstream ss(pageLevelsString); + while (ss.good()) { + unsigned level = ~0u; + ss >> level; + _pageLevels.push_back(level); + } + } + } + + bool isPageLevel(unsigned level) const + { + return std::find(_pageLevels.begin(), _pageLevels.end(), level) != _pageLevels.end(); + } + + std::string getLodPathForBucketBox(const BucketBox& bucketBox) const + { + std::stringstream ss; + ss << "LOD/"; + for (std::vector::const_iterator i = _pageLevels.begin(); i != _pageLevels.end(); ++i) { + if (bucketBox.getStartLevel() <= *i) + break; + ss << bucketBox.getParentBox(*i) << "/"; + } + ss << bucketBox; + return ss.str(); + } + + float getRangeMultiplier() const + { + float rangeMultiplier = 2; + if (!_options) + return rangeMultiplier; + std::stringstream ss(_options->getPluginStringData("SimGear::SPT_RANGE_MULTIPLIER")); + ss >> rangeMultiplier; + return rangeMultiplier; + } + + const osgDB::Options* _options; + std::vector _pageLevels; +}; + ReaderWriterSPT::ReaderWriterSPT() { supportsExtension("spt", "SimGear paged terrain meta database."); @@ -130,9 +194,9 @@ // We get called with different extensions. To make sure search continues, // we need to return FILE_NOT_HANDLED in this case. if (osgDB::getLowerCaseFileExtension(fileName) != "spt") - return ReadResult(osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED); + return ReadResult(ReadResult::FILE_NOT_HANDLED); if (fileName != "state.spt") - return ReadResult(osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND); + return ReadResult(ReadResult::FILE_NOT_FOUND); osg::StateSet* stateSet = new osg::StateSet; stateSet->setAttributeAndModes(new osg::CullFace); @@ -158,39 +222,42 @@ osgDB::ReaderWriter::ReadResult ReaderWriterSPT::readNode(const std::string& fileName, const osgDB::Options* options) const { + LocalOptions localOptions(options); + // The file name without path and without the spt extension std::string strippedFileName = osgDB::getStrippedName(fileName); if (strippedFileName == "earth") - return createTree(BucketBox(0, -90, 360, 180), options, true); + return ReadResult(createTree(BucketBox(-180, -90, 360, 180), localOptions, true)); std::stringstream ss(strippedFileName); BucketBox bucketBox; ss >> bucketBox; if (ss.fail()) - return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND; + return ReadResult::FILE_NOT_FOUND; BucketBox bucketBoxList[2]; unsigned bucketBoxListSize = bucketBox.periodicSplit(bucketBoxList); if (bucketBoxListSize == 0) - return osgDB::ReaderWriter::ReadResult::FILE_NOT_FOUND; + return ReadResult::FILE_NOT_FOUND; if (bucketBoxListSize == 1) - return createTree(bucketBoxList[0], options, true); + return ReadResult(createTree(bucketBoxList[0], localOptions, true)); assert(bucketBoxListSize == 2); osg::ref_ptr group = new osg::Group; - group->addChild(createTree(bucketBoxList[0], options, true)); - group->addChild(createTree(bucketBoxList[1], options, true)); - return group.release(); + group->addChild(createTree(bucketBoxList[0], localOptions, true)); + group->addChild(createTree(bucketBoxList[1], localOptions, true)); + return ReadResult(group); } -osg::Node* -ReaderWriterSPT::createTree(const BucketBox& bucketBox, const osgDB::Options* options, bool topLevel) const +osg::ref_ptr +ReaderWriterSPT::createTree(const BucketBox& bucketBox, const LocalOptions& options, bool topLevel) const { if (bucketBox.getIsBucketSize()) { - return createPagedLOD(bucketBox, options); - } else if (!topLevel && bucketBox.getStartLevel() == 4) { - // We want an other level of indirection for paging + std::string fileName; + fileName = bucketBox.getBucket().gen_index_str() + std::string(".stg"); + return osgDB::readRefNodeFile(fileName, options._options); + } else if (!topLevel && options.isPageLevel(bucketBox.getStartLevel())) { return createPagedLOD(bucketBox, options); } else { BucketBox bucketBoxList[100]; @@ -203,20 +270,20 @@ osg::ref_ptr group = new osg::Group; for (unsigned i = 0; i < numTiles; ++i) { - osg::Node* node = createTree(bucketBoxList[i], options, false); - if (!node) + osg::ref_ptr node = createTree(bucketBoxList[i], options, false); + if (!node.valid()) continue; - group->addChild(node); + group->addChild(node.get()); } if (!group->getNumChildren()) return 0; - return group.release(); + return group; } } -osg::Node* -ReaderWriterSPT::createPagedLOD(const BucketBox& bucketBox, const osgDB::Options* options) const +osg::ref_ptr +ReaderWriterSPT::createPagedLOD(const BucketBox& bucketBox, const LocalOptions& options) const { osg::PagedLOD* pagedLOD = new osg::PagedLOD; @@ -228,45 +295,57 @@ pagedLOD->setCullCallback(new CullCallback); osg::ref_ptr localOptions; - localOptions = static_cast(options->clone(osg::CopyOp())); + localOptions = static_cast(options._options->clone(osg::CopyOp())); // FIXME: // The particle systems have nodes with culling disabled. // PagedLOD nodes with childnodes like this will never expire. // So, for now switch them off. localOptions->setPluginStringData("SimGear::PARTICLESYSTEM", "OFF"); pagedLOD->setDatabaseOptions(localOptions.get()); - - float range; - if (bucketBox.getIsBucketSize()) - range = 200e3; - else - range = 1e6; - - // Add the static sea level textured shell - if (osg::Node* tile = createSeaLevelTile(bucketBox, options)) - pagedLOD->addChild(tile, range, std::numeric_limits::max()); - // Add the paged file name that creates the subtrees on demand - if (bucketBox.getIsBucketSize()) { - std::string fileName; - fileName = bucketBox.getBucket().gen_index_str() + std::string(".stg"); - pagedLOD->setFileName(pagedLOD->getNumChildren(), fileName); - } else { - std::stringstream ss; - ss << bucketBox << ".spt"; - pagedLOD->setFileName(pagedLOD->getNumChildren(), ss.str()); + // The break point for the low level of detail to the high level of detail + float rangeMultiplier = options.getRangeMultiplier(); + float range = rangeMultiplier*sphere.getRadius(); + + // Look for a low level of detail tile + std::string lodPath = options.getLodPathForBucketBox(bucketBox); + const char* extensions[] = { ".btg.gz", ".flt" }; + for (unsigned i = 0; i < sizeof(extensions)/sizeof(extensions[0]); ++i) { + std::string fileName = osgDB::findDataFile(lodPath + extensions[i], options._options); + if (fileName.empty()) + continue; + osg::ref_ptr node = osgDB::readRefNodeFile(fileName, options._options); + if (!node.valid()) + continue; + pagedLOD->addChild(node.get(), range, std::numeric_limits::max()); + break; } + // Add the static sea level textured shell if there is nothing found + if (pagedLOD->getNumChildren() == 0) { + osg::ref_ptr node = createSeaLevelTile(bucketBox, options._options); + if (node.valid()) + pagedLOD->addChild(node.get(), range, std::numeric_limits::max()); + } + + // Add the paged file name that creates the subtrees on demand + std::stringstream ss; + ss << bucketBox << ".spt"; + pagedLOD->setFileName(pagedLOD->getNumChildren(), ss.str()); pagedLOD->setRange(pagedLOD->getNumChildren(), 0.0, range); return pagedLOD; } -osg::Node* -ReaderWriterSPT::createSeaLevelTile(const BucketBox& bucketBox, const osgDB::Options* options) const +osg::ref_ptr +ReaderWriterSPT::createSeaLevelTile(const BucketBox& bucketBox, const LocalOptions& options) const { - if (options->getPluginStringData("SimGear::FG_EARTH") != "ON") + if (options._options->getPluginStringData("SimGear::FG_EARTH") != "ON") return 0; + SGSpheref sphere = bucketBox.getBoundingSphere(); + osg::Matrixd transform; + transform.makeTranslate(toOsg(-sphere.getCenter())); + osg::Vec3Array* vertices = new osg::Vec3Array; osg::Vec3Array* normals = new osg::Vec3Array; osg::Vec2Array* texCoords = new osg::Vec2Array; @@ -284,7 +363,7 @@ SGVec2f t[6]; unsigned num = bucketBox.getTileTriangles(i, j, incx, incy, v, n, t); for (unsigned k = 0; k < num; ++k) { - vertices->push_back(toOsg(v[k])); + vertices->push_back(transform.preMult(toOsg(v[k]))); normals->push_back(toOsg(n[k])); texCoords->push_back(toOsg(t[k])); } @@ -299,6 +378,8 @@ colors->push_back(osg::Vec4(1, 1, 1, 1)); osg::Geometry* geometry = new osg::Geometry; + geometry->setDataVariance(osg::Object::STATIC); + geometry->setUseVertexBufferObjects(true); geometry->setVertexArray(vertices); geometry->setNormalArray(normals); geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); @@ -306,27 +387,36 @@ geometry->setColorBinding(osg::Geometry::BIND_OVERALL); geometry->setTexCoordArray(0, texCoords); - geometry->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::TRIANGLES, 0, vertices->size())); + osg::DrawArrays* drawArrays = new osg::DrawArrays(osg::DrawArrays::TRIANGLES, 0, vertices->size()); + drawArrays->setDataVariance(osg::Object::STATIC); + geometry->addPrimitiveSet(drawArrays); osg::Geode* geode = new osg::Geode; + geode->setDataVariance(osg::Object::STATIC); geode->addDrawable(geometry); - geode->setStateSet(getLowLODStateSet(options)); + osg::ref_ptr stateSet = getLowLODStateSet(options); + geode->setStateSet(stateSet.get()); + + transform.makeTranslate(toOsg(sphere.getCenter())); + osg::MatrixTransform* matrixTransform = new osg::MatrixTransform(transform); + matrixTransform->setDataVariance(osg::Object::STATIC); + matrixTransform->addChild(geode); - return geode; + return matrixTransform; } -osg::StateSet* -ReaderWriterSPT::getLowLODStateSet(const osgDB::Options* options) const +osg::ref_ptr +ReaderWriterSPT::getLowLODStateSet(const LocalOptions& options) const { osg::ref_ptr localOptions; - localOptions = static_cast(options->clone(osg::CopyOp())); + localOptions = static_cast(options._options->clone(osg::CopyOp())); localOptions->setObjectCacheHint(osgDB::Options::CACHE_ALL); - osg::ref_ptr object = osgDB::readObjectFile("state.spt", localOptions.get()); + osg::ref_ptr object = osgDB::readRefObjectFile("state.spt", localOptions.get()); if (!dynamic_cast(object.get())) return 0; - return static_cast(object.release()); + return static_cast(object.get()); } } // namespace simgear diff -Nru simgear-2.10.0/simgear/scene/tgdb/ReaderWriterSPT.hxx simgear-3.0.0/simgear/scene/tgdb/ReaderWriterSPT.hxx --- simgear-2.10.0/simgear/scene/tgdb/ReaderWriterSPT.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/ReaderWriterSPT.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -1,6 +1,6 @@ // ReaderWriterSPT.cxx -- Provide a paged database for flightgear scenery. // -// Copyright (C) 2010 - 2011 Mathias Froehlich +// Copyright (C) 2010 - 2013 Mathias Froehlich // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -37,10 +37,12 @@ virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& fileName, const osgDB::Options* options) const; protected: - osg::Node* createTree(const BucketBox& bucketBox, const osgDB::Options* options, bool topLevel) const; - osg::Node* createPagedLOD(const BucketBox& bucketBox, const osgDB::Options* options) const; - osg::Node* createSeaLevelTile(const BucketBox& bucketBox, const osgDB::Options* options) const; - osg::StateSet* getLowLODStateSet(const osgDB::Options* options) const; + struct LocalOptions; + + osg::ref_ptr createTree(const BucketBox& bucketBox, const LocalOptions& options, bool topLevel) const; + osg::ref_ptr createPagedLOD(const BucketBox& bucketBox, const LocalOptions& options) const; + osg::ref_ptr createSeaLevelTile(const BucketBox& bucketBox, const LocalOptions& options) const; + osg::ref_ptr getLowLODStateSet(const LocalOptions& options) const; private: struct CullCallback; diff -Nru simgear-2.10.0/simgear/scene/tgdb/ReaderWriterSTG.cxx simgear-3.0.0/simgear/scene/tgdb/ReaderWriterSTG.cxx --- simgear-2.10.0/simgear/scene/tgdb/ReaderWriterSTG.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/ReaderWriterSTG.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -37,12 +38,14 @@ #include #include +#include #include #include #include -#include -#include +#include #include +#include +#include #include #include @@ -109,6 +112,66 @@ int _size; }; + class DelayLoadReadFileCallback : public OptionsReadFileCallback { + public: + virtual osgDB::ReaderWriter::ReadResult + readNode(const std::string&, const osgDB::Options*) + { + osg::ref_ptr group = new osg::Group; + group->setName("STG-group-A"); + group->setDataVariance(osg::Object::STATIC); + + for (std::list<_ObjectStatic>::iterator i = _objectStaticList.begin(); i != _objectStaticList.end(); ++i) { + osg::ref_ptr node; + if (i->_proxy) { + osg::ref_ptr proxy = new osg::ProxyNode; + proxy->setName("proxyNode"); + proxy->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER); + proxy->setFileName(0, i->_name); + proxy->setDatabaseOptions(i->_options.get()); + node = proxy; + } else { + node = osgDB::readRefNodeFile(i->_name, i->_options.get()); + if (!node.valid()) { + SG_LOG(SG_TERRAIN, SG_ALERT, i->_errorLocation << ": Failed to load " + << i->_token << " '" << i->_name << "'"); + continue; + } + } + if (SGPath(i->_name).lower_extension() == "ac") + node->setNodeMask(~simgear::MODELLIGHT_BIT); + + osg::Matrix matrix; + matrix = makeZUpFrame(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev)); + matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_hdg), osg::Vec3(0, 0, 1))); + matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_pitch), osg::Vec3(0, 1, 0))); + matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_roll), osg::Vec3(1, 0, 0))); + + osg::MatrixTransform* matrixTransform; + matrixTransform = new osg::MatrixTransform(matrix); + matrixTransform->setName("positionStaticObject"); + matrixTransform->setDataVariance(osg::Object::STATIC); + matrixTransform->addChild(node.get()); + group->addChild(matrixTransform); + } + + simgear::AirportSignBuilder signBuilder(_options->getMaterialLib(), _bucket.get_center()); + for (std::list<_Sign>::iterator i = _signList.begin(); i != _signList.end(); ++i) + signBuilder.addSign(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev), i->_hdg, i->_name, i->_size); + if (signBuilder.getSignsGroup()) + group->addChild(signBuilder.getSignsGroup()); + + return group.release(); + } + + std::list<_ObjectStatic> _objectStaticList; + std::list<_Sign> _signList; + + /// The original options to use for this bunch of models + osg::ref_ptr _options; + SGBucket _bucket; + }; + _ModelBin() : _foundBase(false) { } @@ -122,9 +185,25 @@ SGPath path = filePath; path.append(".."); path.append(".."); path.append(".."); sharedOptions->getDatabasePathList().push_back(path.str()); + + // ensure Models directory synced via TerraSync is searched before the copy in + // FG_ROOT, so that updated models can be used. + std::string terrasync_root = options->getPluginStringData("SimGear::TERRASYNC_ROOT"); + if (!terrasync_root.empty()) { + sharedOptions->getDatabasePathList().push_back(terrasync_root); + } + std::string fg_root = options->getPluginStringData("SimGear::FG_ROOT"); sharedOptions->getDatabasePathList().push_back(fg_root); + // TODO how should we handle this for OBJECT_SHARED? + sharedOptions->setModelData + ( + sharedOptions->getModelData() + ? sharedOptions->getModelData()->clone() + : 0 + ); + return sharedOptions.release(); } SGReaderWriterOptions* staticOptions(const std::string& filePath, const osgDB::Options* options) @@ -136,6 +215,15 @@ staticOptions->getDatabasePathList().push_back(filePath); staticOptions->setObjectCacheHint(osgDB::Options::CACHE_NONE); + // Every model needs its own SGModelData to ensure load/unload is + // working properly + staticOptions->setModelData + ( + staticOptions->getModelData() + ? staticOptions->getModelData()->clone() + : 0 + ); + return staticOptions.release(); } @@ -291,7 +379,8 @@ osg::ref_ptr terrainGroup = new osg::Group; terrainGroup->setDataVariance(osg::Object::STATIC); - + terrainGroup->setName("terrain"); + if (_foundBase) { for (std::list<_Object>::iterator i = _objectList.begin(); i != _objectList.end(); ++i) { osg::ref_ptr node; @@ -304,10 +393,11 @@ terrainGroup->addChild(node.get()); } } else { - SG_LOG(SG_TERRAIN, SG_INFO, " Generating ocean tile"); + SG_LOG(SG_TERRAIN, SG_INFO, " Generating ocean tile: " << bucket.gen_base_path() << "/" << bucket.gen_index_str()); osg::Node* node = SGOceanTile(bucket, options->getMaterialLib()); if (node) { + node->setName("SGOceanTile"); terrainGroup->addChild(node); } else { SG_LOG( SG_TERRAIN, SG_ALERT, @@ -326,58 +416,36 @@ continue; i->_elev += elevation(*terrainGroup, SGGeod::fromDeg(i->_lon, i->_lat)); } - - osg::ref_ptr modelGroup = new osg::Group; - modelGroup->setDataVariance(osg::Object::STATIC); - for (std::list<_ObjectStatic>::iterator i = _objectStaticList.begin(); i != _objectStaticList.end(); ++i) { - osg::ref_ptr node; - if (i->_proxy) { - osg::ref_ptr proxy = new osg::ProxyNode; - proxy->setLoadingExternalReferenceMode(osg::ProxyNode::DEFER_LOADING_TO_DATABASE_PAGER); - proxy->setFileName(0, i->_name); - proxy->setDatabaseOptions(i->_options.get()); - node = proxy; - } else { - node = osgDB::readRefNodeFile(i->_name, i->_options.get()); - if (!node.valid()) { - SG_LOG(SG_TERRAIN, SG_ALERT, i->_errorLocation << ": Failed to load " - << i->_token << " '" << i->_name << "'"); - continue; - } - } - if (SGPath(i->_name).lower_extension() == "ac") - node->setNodeMask(~simgear::MODELLIGHT_BIT); + if (_objectStaticList.empty() && _signList.empty()) { + // The simple case, just return the terrain group + return terrainGroup.release(); + } else { + osg::PagedLOD* pagedLOD = new osg::PagedLOD; + pagedLOD->setCenterMode(osg::PagedLOD::USE_BOUNDING_SPHERE_CENTER); + pagedLOD->setName("pagedObjectLOD"); + + // This should be visible in any case. + // If this is replaced by some lower level of detail, the parent LOD node handles this. + pagedLOD->addChild(terrainGroup, 0, std::numeric_limits::max()); + + // we just need to know about the read file callback that itself holds the data + osg::ref_ptr readFileCallback = new DelayLoadReadFileCallback; + readFileCallback->_objectStaticList = _objectStaticList; + readFileCallback->_signList = _signList; + readFileCallback->_options = options; + readFileCallback->_bucket = bucket; + osg::ref_ptr callbackOptions = new osgDB::Options; + callbackOptions->setReadFileCallback(readFileCallback.get()); + pagedLOD->setDatabaseOptions(callbackOptions.get()); - osg::Matrix matrix; - matrix = makeZUpFrame(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev)); - matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_hdg), osg::Vec3(0, 0, 1))); - matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_pitch), osg::Vec3(0, 1, 0))); - matrix.preMultRotate(osg::Quat(SGMiscd::deg2rad(i->_roll), osg::Vec3(1, 0, 0))); - - osg::MatrixTransform* matrixTransform; - matrixTransform = new osg::MatrixTransform(matrix); - matrixTransform->setDataVariance(osg::Object::STATIC); - matrixTransform->addChild(node.get()); - modelGroup->addChild(matrixTransform); + pagedLOD->setFileName(pagedLOD->getNumChildren(), "Dummy name - use the stored data in the read file callback"); + pagedLOD->setRange(pagedLOD->getNumChildren(), 0, 30000); + + return pagedLOD; } - - simgear::AirportSignBuilder signBuilder(options->getMaterialLib(), bucket.get_center()); - for (std::list<_Sign>::iterator i = _signList.begin(); i != _signList.end(); ++i) - signBuilder.addSign(SGGeod::fromDegM(i->_lon, i->_lat, i->_elev), i->_hdg, i->_name, i->_size); - if (signBuilder.getSignsGroup()) - modelGroup->addChild(signBuilder.getSignsGroup()); - - osg::LOD* lod = new osg::LOD; - lod->setDataVariance(osg::Object::STATIC); - if (terrainGroup->getNumChildren()) - lod->addChild(terrainGroup.get(), 0, std::numeric_limits::max()); - if (modelGroup->getNumChildren()) - lod->addChild(modelGroup.get(), 0, 30000); - - return lod; } - + bool _foundBase; std::list<_Object> _objectList; std::list<_ObjectStatic> _objectStaticList; diff -Nru simgear-2.10.0/simgear/scene/tgdb/SGBuildingBin.cxx simgear-3.0.0/simgear/scene/tgdb/SGBuildingBin.cxx --- simgear-2.10.0/simgear/scene/tgdb/SGBuildingBin.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/SGBuildingBin.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -61,14 +61,13 @@ namespace simgear { - + typedef std::map > BuildingStateSetMap; static BuildingStateSetMap statesetmap; -static int numBuildings; typedef std::map > EffectMap; static EffectMap buildingEffectMap; - + // Building instance scheme: // vertex - local position of vertices, with 0,0,0 being the center front. // fog coord - rotation @@ -89,7 +88,7 @@ const Geometry* geom = static_cast(&drawable); const Vec3Array* v = static_cast(geom->getVertexArray()); const Vec4Array* pos = static_cast(geom->getColorArray()); - + Geometry::PrimitiveSetList primSets = geom->getPrimitiveSetList(); for (Geometry::PrimitiveSetList::const_iterator psitr = primSets.begin(), psend = primSets.end(); psitr != psend; @@ -105,130 +104,131 @@ bb.expandBy(pt); } } - return bb; + return bb; } // Set up the building set based on the material definitions SGBuildingBin::SGBuildingBin(const SGMaterial *mat) { - - material_name = mat->get_names()[0]; + + material_name = new std::string(mat->get_names()[0]); SG_LOG(SG_TERRAIN, SG_DEBUG, "Building material " << material_name); - texture = mat->get_building_texture(); - lightMap = mat->get_building_lightmap(); + texture = new std::string(mat->get_building_texture()); + lightMap = new std::string(mat->get_building_lightmap()); SG_LOG(SG_TERRAIN, SG_DEBUG, "Building texture " << texture); - + // Generate a random seed for the building generation. mt seed; mt_init(&seed, unsigned(123)); - + smallSharedGeometry = new osg::Geometry(); mediumSharedGeometry = new osg::Geometry(); largeSharedGeometry = new osg::Geometry(); - + smallBuildingMaxRadius = std::max(mat->get_building_small_max_depth() * 0.5, mat->get_building_small_max_width() * 0.5); mediumBuildingMaxRadius = std::max(mat->get_building_medium_max_depth() * 0.5, mat->get_building_medium_max_width() * 0.5); largeBuildingMaxRadius = std::max(mat->get_building_large_max_depth() * 0.5, mat->get_building_large_max_width() * 0.5); - + smallBuildingMaxDepth = mat->get_building_small_max_depth(); mediumBuildingMaxDepth = mat->get_building_medium_max_depth(); - largeBuildingMaxDepth = mat->get_building_large_max_depth(); - + largeBuildingMaxDepth = mat->get_building_large_max_depth(); + smallBuildingFraction = mat->get_building_small_fraction(); mediumBuildingFraction = mat->get_building_medium_fraction(); - + + buildingRange = mat->get_building_range(); + SG_LOG(SG_TERRAIN, SG_DEBUG, "Building fractions " << smallBuildingFraction << " " << mediumBuildingFraction); - - + + // TODO: Reverse this - otherwise we never get any large buildings! - BuildingType types[] = { SGBuildingBin::SMALL, SGBuildingBin::MEDIUM, SGBuildingBin::LARGE }; + BuildingType types[] = { SGBuildingBin::SMALL, SGBuildingBin::MEDIUM, SGBuildingBin::LARGE }; BuildingList lists[] = { SGBuildingBin::smallBuildings, SGBuildingBin::mediumBuildings, SGBuildingBin::largeBuildings }; ref_ptr geometries[] = { smallSharedGeometry, mediumSharedGeometry, largeSharedGeometry }; - + for (int bt=0; bt < 3; bt++) { SGBuildingBin::BuildingType buildingtype = types[bt]; ref_ptr sharedGeometry = geometries[bt]; BuildingList buildings = lists[bt]; - + osg::ref_ptr v = new osg::Vec3Array; osg::ref_ptr t = new osg::Vec2Array; osg::ref_ptr n = new osg::Vec3Array; - + v->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING); t->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING); n->reserve(BUILDING_SET_SIZE * VERTICES_PER_BUILDING); - - sharedGeometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); + sharedGeometry->setFogCoordBinding(osg::Geometry::BIND_PER_VERTEX); sharedGeometry->setComputeBoundingBoxCallback(new BuildingBoundingBoxCallback); sharedGeometry->setUseDisplayList(false); - - for (unsigned int j = 0; j < BUILDING_SET_SIZE; j++) { + + for (unsigned int j = 0; j < BUILDING_SET_SIZE; j++) { float width; float depth; int floors; float height; bool pitched; - + if (buildingtype == SGBuildingBin::SMALL) { // Small building width = mat->get_building_small_min_width() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_small_max_width() - mat->get_building_small_min_width()); depth = mat->get_building_small_min_depth() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_small_max_depth() - mat->get_building_small_min_depth()); floors = SGMisc::round(mat->get_building_small_min_floors() + mt_rand(&seed) * (mat->get_building_small_max_floors() - mat->get_building_small_min_floors())); height = floors * (2.8 + mt_rand(&seed)); - + // Small buildings are never deeper than they are wide. if (depth > width) { depth = width; } - + pitched = (mt_rand(&seed) < mat->get_building_small_pitch()); } else if (buildingtype == SGBuildingBin::MEDIUM) { width = mat->get_building_medium_min_width() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_medium_max_width() - mat->get_building_medium_min_width()); depth = mat->get_building_medium_min_depth() + mt_rand(&seed) * mt_rand(&seed) * (mat->get_building_medium_max_depth() - mat->get_building_medium_min_depth()); floors = SGMisc::round(mat->get_building_medium_min_floors() + mt_rand(&seed) * (mat->get_building_medium_max_floors() - mat->get_building_medium_min_floors())); height = floors * (2.8 + mt_rand(&seed)); - + while ((height > width) && (floors > mat->get_building_medium_min_floors())) { // Ensure that medium buildings aren't taller than they are wide floors--; - height = floors * (2.8 + mt_rand(&seed)); + height = floors * (2.8 + mt_rand(&seed)); } - - pitched = (mt_rand(&seed) < mat->get_building_medium_pitch()); + + pitched = (mt_rand(&seed) < mat->get_building_medium_pitch()); } else { width = mat->get_building_large_min_width() + mt_rand(&seed) * (mat->get_building_large_max_width() - mat->get_building_large_min_width()); depth = mat->get_building_large_min_depth() + mt_rand(&seed) * (mat->get_building_large_max_depth() - mat->get_building_large_min_depth()); - floors = SGMisc::round(mat->get_building_large_min_floors() + mt_rand(&seed) * (mat->get_building_large_max_floors() - mat->get_building_large_min_floors())); + floors = SGMisc::round(mat->get_building_large_min_floors() + mt_rand(&seed) * (mat->get_building_large_max_floors() - mat->get_building_large_min_floors())); height = floors * (2.8 + mt_rand(&seed)); - pitched = (mt_rand(&seed) < mat->get_building_large_pitch()); + pitched = (mt_rand(&seed) < mat->get_building_large_pitch()); } - - Building building = Building(buildingtype, - width, - depth, - height, + + Building building = Building(buildingtype, + width, + depth, + height, floors, - pitched); - + pitched); + buildings.push_back(building); // Now create an OSG Geometry based on the Building float cw = 0.5f * building.width; float cd = building.depth; float ch = building.height; - + // 0,0,0 is the bottom center of the front - // face, e.g. where the front door would be - + // face, e.g. where the front door would be + // BASEMENT // This exteds 10m below the main section - // Front face + // Front face v->push_back( osg::Vec3( 0, -cw, -10) ); // bottom right v->push_back( osg::Vec3( 0, cw, -10) ); // bottom left v->push_back( osg::Vec3( 0, cw, 0) ); // top left v->push_back( osg::Vec3( 0, -cw, 0) ); // top right - + for (int i=0; i<4; ++i) n->push_back( osg::Vec3(1, 0, 0) ); // normal - + // Left face v->push_back( osg::Vec3( -cd, -cw, -10) ); // bottom right v->push_back( osg::Vec3( 0, -cw, -10) ); // bottom left @@ -243,10 +243,10 @@ v->push_back( osg::Vec3( -cd, -cw, -10) ); // bottom left v->push_back( osg::Vec3( -cd, -cw, 0) ); // top left v->push_back( osg::Vec3( -cd, cw, 0) ); // top right - + for (int i=0; i<4; ++i) n->push_back( osg::Vec3(-1, 0, 0) ); // normal - + // Right face v->push_back( osg::Vec3( 0, cw, -10) ); // bottom right v->push_back( osg::Vec3( -cd, cw, -10) ); // bottom left @@ -254,18 +254,18 @@ v->push_back( osg::Vec3( 0, cw, 0) ); // top right for (int i=0; i<4; ++i) - n->push_back( osg::Vec3(0, 1, 0) ); // normal - + n->push_back( osg::Vec3(0, 1, 0) ); // normal + // MAIN BODY - // Front face + // Front face v->push_back( osg::Vec3( 0, -cw, 0) ); // bottom right v->push_back( osg::Vec3( 0, cw, 0) ); // bottom left v->push_back( osg::Vec3( 0, cw, ch) ); // top left v->push_back( osg::Vec3( 0, -cw, ch) ); // top right - + for (int i=0; i<4; ++i) n->push_back( osg::Vec3(1, 0, 0) ); // normal - + // Left face v->push_back( osg::Vec3( -cd, -cw, 0) ); // bottom right v->push_back( osg::Vec3( 0, -cw, 0) ); // bottom left @@ -280,10 +280,10 @@ v->push_back( osg::Vec3( -cd, -cw, 0) ); // bottom left v->push_back( osg::Vec3( -cd, -cw, ch) ); // top left v->push_back( osg::Vec3( -cd, cw, ch) ); // top right - + for (int i=0; i<4; ++i) n->push_back( osg::Vec3(-1, 0, 0) ); // normal - + // Right face v->push_back( osg::Vec3( 0, cw, 0) ); // bottom right v->push_back( osg::Vec3( -cd, cw, 0) ); // bottom left @@ -292,25 +292,25 @@ for (int i=0; i<4; ++i) n->push_back( osg::Vec3(0, 1, 0) ); // normal - + // ROOF - if (building.pitched) { - + if (building.pitched) { + // Front pitched roof v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom right v->push_back( osg::Vec3( 0, cw, ch) ); // bottom left v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top left v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top right - + for (int i=0; i<4; ++i) n->push_back( osg::Vec3(0.707, 0, 0.707) ); // normal - + // Left pitched roof v->push_back( osg::Vec3( -cd, -cw, ch) ); // bottom right v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom left v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top left v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top right - + for (int i=0; i<4; ++i) n->push_back( osg::Vec3(0, -1, 0) ); // normal @@ -319,37 +319,37 @@ v->push_back( osg::Vec3( -cd, -cw, ch) ); // bottom left v->push_back( osg::Vec3(-0.5*cd, -cw, ch+3) ); // top left v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top right - + for (int i=0; i<4; ++i) - n->push_back( osg::Vec3(-0.707, 0, 0.707) ); // normal + n->push_back( osg::Vec3(-0.707, 0, 0.707) ); // normal // Right pitched roof v->push_back( osg::Vec3( 0, cw, ch) ); // bottom right v->push_back( osg::Vec3( -cd, cw, ch) ); // bottom left v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top left v->push_back( osg::Vec3(-0.5*cd, cw, ch+3) ); // top right - + for (int i=0; i<4; ++i) n->push_back( osg::Vec3(0, 1, 0) ); // normal - } else { - // If the roof isn't pitched, we still generate the + } else { + // If the roof isn't pitched, we still generate the // vertices for simplicity later. - + // Top of the roof v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom right v->push_back( osg::Vec3( 0, cw, ch) ); // bottom left v->push_back( osg::Vec3(-cd, cw, ch) ); // top left v->push_back( osg::Vec3(-cd, -cw, ch) ); // top right - + for (int i=0; i<4; ++i) n->push_back( osg::Vec3(0, 0, 1) ); // normal - + // Left non-pitched roof v->push_back( osg::Vec3( -cd, -cw, ch) ); // bottom right v->push_back( osg::Vec3( 0, -cw, ch) ); // bottom left v->push_back( osg::Vec3( 0, -cw, ch) ); // top left v->push_back( osg::Vec3( -cd, -cw, ch) ); // top right - + for (int i=0; i<4; ++i) n->push_back( osg::Vec3(0, -1, 0) ); // normal @@ -358,25 +358,25 @@ v->push_back( osg::Vec3(-cd, -cw, ch) ); // bottom left v->push_back( osg::Vec3(-cd, -cw, ch) ); // top left v->push_back( osg::Vec3(-cd, cw, ch) ); // top right - + for (int i=0; i<4; ++i) - n->push_back( osg::Vec3(1, 0, 0) ); // normal + n->push_back( osg::Vec3(1, 0, 0) ); // normal // Right pitched roof v->push_back( osg::Vec3( 0, cw, ch) ); // bottom right v->push_back( osg::Vec3(-cd, cw, ch) ); // bottom left v->push_back( osg::Vec3(-cd, cw, ch) ); // top left v->push_back( osg::Vec3( 0, cw, ch) ); // top right - + for (int i=0; i<4; ++i) n->push_back( osg::Vec3(0, 1, 0) ); // normal } - + // The 1024x1024 texture is split into 32x16 blocks. // For a small building, each block is 6m wide and 3m high. // For a medium building, each block is 10m wide and 3m high. // For a large building, each block is 20m wide and 3m high - + if (building.type == SGBuildingBin::SMALL) { // Small buildings are represented on the bottom 5 rows of 3 floors int row = ((int) (mt_rand(&seed) * 1000)) % 5; @@ -388,8 +388,8 @@ float back_x = 384.0/1024.0 + 32.0 / 1024.0 * round((float) building.depth/ 6.0f); // BASEMENT - uses the baseline texture - for (unsigned int i = 0; i < 16; i++) { - t->push_back( osg::Vec2( left_x, base_y) ); + for (unsigned int i = 0; i < 16; i++) { + t->push_back( osg::Vec2( left_x, base_y) ); } // MAIN BODY // Front @@ -397,19 +397,19 @@ t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Left t->push_back( osg::Vec2( front_x, base_y) ); // bottom right t->push_back( osg::Vec2( back_x, base_y) ); // bottom left t->push_back( osg::Vec2( back_x, top_y ) ); // top left t->push_back( osg::Vec2( front_x, top_y ) ); // top right - + // Back (same as front for the moment) t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Right (same as left for the moment) t->push_back( osg::Vec2( front_x, base_y) ); // bottom right t->push_back( osg::Vec2( back_x, base_y) ); // bottom left @@ -417,32 +417,32 @@ t->push_back( osg::Vec2( front_x, top_y ) ); // top right // ROOF - if (building.pitched) { + if (building.pitched) { // Use the entire height of the roof texture - top_y = base_y + 16.0 * 3.0 / 1024.0; + top_y = base_y + 16.0 * 3.0 / 1024.0; left_x = 512/1024.0 + 32.0 / 1024.0 * round(building.width / 6.0f); right_x = 512/1024.0; front_x = 480.0/1024.0; back_x = 512.0/1024.0; - + // Front t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Left t->push_back( osg::Vec2( front_x, base_y) ); // bottom right t->push_back( osg::Vec2( back_x, base_y) ); // bottom left t->push_back( osg::Vec2( back_x, top_y ) ); // top left t->push_back( osg::Vec2( front_x, top_y ) ); // top right - + // Back (same as front for the moment) t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Right (same as left for the moment) t->push_back( osg::Vec2( front_x, base_y) ); // bottom right t->push_back( osg::Vec2( back_x, base_y) ); // bottom left @@ -453,31 +453,31 @@ left_x = 640.0/1024.0; right_x = 512.0/1024.0; // Use the entire height of the roof texture - top_y = base_y + 16.0 * 3.0 / 1024.0; - + top_y = base_y + 16.0 * 3.0 / 1024.0; + // Flat roofs still have 4 surfaces, so we need to set the textures - for (int i=0; i<4; ++i) { + for (int i=0; i<4; ++i) { t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right } } - + } - - if (building.type == SGBuildingBin::MEDIUM) + + if (building.type == SGBuildingBin::MEDIUM) { - int column = ((int) (mt_rand(&seed) * 1000)) % 5; + int column = ((int) (mt_rand(&seed) * 1000)) % 5; float base_y = 288 / 1024.0; float top_y = base_y + 16.0 * (float) building.floors / 1024.0; float left_x = column * 192.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 10.0f); float right_x = column * 192.0 /1024.0; // BASEMENT - uses the baseline texture - for (unsigned int i = 0; i < 16; i++) { - t->push_back( osg::Vec2( left_x, base_y) ); - } + for (unsigned int i = 0; i < 16; i++) { + t->push_back( osg::Vec2( left_x, base_y) ); + } // MAIN BODY // Front @@ -485,19 +485,19 @@ t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Left t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Back (same as front for the moment) t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Right (same as left for the moment) t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left @@ -505,30 +505,30 @@ t->push_back( osg::Vec2( right_x, top_y ) ); // top right // ROOF - if (building.pitched) { + if (building.pitched) { base_y = 288.0/1024.0; top_y = 576.0/1024.0; left_x = 960.0/1024.0; right_x = 1.0; - + // Front t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Left t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Back (same as front for the moment) t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Right (same as left for the moment) t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left @@ -540,9 +540,9 @@ top_y = 576.0/1024.0; left_x = column * 192.0 /1024.0; right_x = (column + 1)* 192.0 /1024.0; - + // Flat roofs still have 4 surfaces - for (int i=0; i<4; ++i) { + for (int i=0; i<4; ++i) { t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left @@ -553,16 +553,16 @@ if (building.type == SGBuildingBin::LARGE) { - int column = ((int) (mt_rand(&seed) * 1000)) % 8; + int column = ((int) (mt_rand(&seed) * 1000)) % 8; float base_y = 576 / 1024.0; float top_y = base_y + 16.0 * (float) building.floors / 1024.0; float left_x = column * 128.0 /1024.0 + 32.0 / 1024.0 * round((float) building.width / 20.0f); - float right_x = column * 128.0 /1024.0; + float right_x = column * 128.0 /1024.0; // BASEMENT - uses the baseline texture - for (unsigned int i = 0; i < 16; i++) { - t->push_back( osg::Vec2( left_x, base_y) ); - } + for (unsigned int i = 0; i < 16; i++) { + t->push_back( osg::Vec2( left_x, base_y) ); + } // MAIN BODY // Front @@ -570,19 +570,19 @@ t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Left t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Back (same as front for the moment) t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Right (same as left for the moment) t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left @@ -590,7 +590,7 @@ t->push_back( osg::Vec2( right_x, top_y ) ); // top right // ROOF - if (building.pitched) { + if (building.pitched) { base_y = 896/1024.0; top_y = 1.0; // Front @@ -598,19 +598,19 @@ t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Left t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Back (same as front for the moment) t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left t->push_back( osg::Vec2( right_x, top_y ) ); // top right - + // Right (same as left for the moment) t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left @@ -620,9 +620,9 @@ // Flat roof base_y = 896/1024.0; top_y = 1.0; - + // Flat roofs still have 4 surfaces - for (int i=0; i<4; ++i) { + for (int i=0; i<4; ++i) { t->push_back( osg::Vec2( right_x, base_y) ); // bottom right t->push_back( osg::Vec2( left_x, base_y) ); // bottom left t->push_back( osg::Vec2( left_x, top_y ) ); // top left @@ -631,96 +631,100 @@ } } } - + // Set the vertex, texture and normals. Colors will be set per-instance // later. sharedGeometry->setVertexArray(v); sharedGeometry->setTexCoordArray(0, t); sharedGeometry->setNormalArray(n); + + // Work around a bug in OSG 3.2.0 where BIND_PER_VERTEX appears + // not to take effect if the normal array is set subsequently. + sharedGeometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); } } - - void SGBuildingBin::insert(SGVec3f p, float r, BuildingType type) { - + + void SGBuildingBin::insert(SGVec3f p, float r, BuildingType type) { + if (type == SGBuildingBin::SMALL) { - smallBuildingLocations.push_back(BuildingInstance(p, r, &smallBuildings, smallSharedGeometry)); + smallBuildingLocations.push_back(BuildingInstance(p, r, &smallBuildings, smallSharedGeometry)); } - + if (type == SGBuildingBin::MEDIUM) { - mediumBuildingLocations.push_back(BuildingInstance(p, r, &mediumBuildings, mediumSharedGeometry)); + mediumBuildingLocations.push_back(BuildingInstance(p, r, &mediumBuildings, mediumSharedGeometry)); } if (type == SGBuildingBin::LARGE) { - largeBuildingLocations.push_back(BuildingInstance(p, r, &largeBuildings, largeSharedGeometry)); - } + largeBuildingLocations.push_back(BuildingInstance(p, r, &largeBuildings, largeSharedGeometry)); + } } int SGBuildingBin::getNumBuildings() { - return smallBuildingLocations.size() + mediumBuildingLocations.size() + largeBuildingLocations.size(); + return smallBuildingLocations.size() + mediumBuildingLocations.size() + largeBuildingLocations.size(); } - - bool SGBuildingBin::checkMinDist (SGVec3f p, float radius) { + + bool SGBuildingBin::checkMinDist (SGVec3f p, float radius) { BuildingInstanceList::iterator iter; - + float r = (radius + smallBuildingMaxRadius) * (radius + smallBuildingMaxRadius); for (iter = smallBuildingLocations.begin(); iter != smallBuildingLocations.end(); ++iter) { if (iter->getDistSqr(p) < r) { - return false; - } + return false; + } } - + r = (radius + mediumBuildingMaxRadius) * (radius + mediumBuildingMaxRadius); for (iter = mediumBuildingLocations.begin(); iter != mediumBuildingLocations.end(); ++iter) { if (iter->getDistSqr(p) < r) { - return false; - } + return false; + } } - + r = (radius + largeBuildingMaxRadius) * (radius + largeBuildingMaxRadius); for (iter = largeBuildingLocations.begin(); iter != largeBuildingLocations.end(); ++iter) { if (iter->getDistSqr(p) < r) { - return false; - } + return false; + } } - + return true; } - + SGBuildingBin::BuildingType SGBuildingBin::getBuildingType(float roll) { - + if (roll < smallBuildingFraction) { - return SGBuildingBin::SMALL; + return SGBuildingBin::SMALL; } - + if (roll < (smallBuildingFraction + mediumBuildingFraction)) { return SGBuildingBin::MEDIUM; } - - return SGBuildingBin::LARGE; + + return SGBuildingBin::LARGE; } float SGBuildingBin::getBuildingMaxRadius(BuildingType type) { - + if (type == SGBuildingBin::SMALL) return smallBuildingMaxRadius; if (type == SGBuildingBin::MEDIUM) return mediumBuildingMaxRadius; if (type == SGBuildingBin::LARGE) return largeBuildingMaxRadius; - + return 0; } - + float SGBuildingBin::getBuildingMaxDepth(BuildingType type) { - + if (type == SGBuildingBin::SMALL) return smallBuildingMaxDepth; if (type == SGBuildingBin::MEDIUM) return mediumBuildingMaxDepth; if (type == SGBuildingBin::LARGE) return largeBuildingMaxDepth; - + return 0; } - + ref_ptr SGBuildingBin::createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options) { ref_ptr effect; - EffectMap::iterator iter = buildingEffectMap.find(texture); + EffectMap::iterator iter = buildingEffectMap.find(*texture); if ((iter == buildingEffectMap.end())|| (!iter->second.lock(effect))) @@ -730,34 +734,35 @@ SGPropertyNode* params = makeChild(effectProp, "parameters"); // Main texture - n=0 params->getChild("texture", 0, true)->getChild("image", 0, true) - ->setStringValue(texture); + ->setStringValue(*texture); // Light map - n=3 params->getChild("texture", 3, true)->getChild("image", 0, true) - ->setStringValue(lightMap); - + ->setStringValue(*lightMap); + effect = makeEffect(effectProp, true, options); if (iter == buildingEffectMap.end()) - buildingEffectMap.insert(EffectMap::value_type(texture, effect)); + buildingEffectMap.insert(EffectMap::value_type(*texture, effect)); else iter->second = effect; // update existing, but empty observer } - + ref_ptr group = new osg::Group(); - - // Now, create a quadbuilding for the buildings. - - BuildingInstanceList locs[] = { smallBuildingLocations, - SGBuildingBin::mediumBuildingLocations, + + // Now, create a quadbuilding for the buildings. + + BuildingInstanceList locs[] = { smallBuildingLocations, + SGBuildingBin::mediumBuildingLocations, SGBuildingBin::largeBuildingLocations }; - + for (int i = 0; i < 3; i++) { + // Create a quad tree. Only small and medium buildings are faded out. BuildingGeometryQuadtree quadbuilding(GetBuildingCoord(), AddBuildingLeafObject(), SG_BUILDING_QUAD_TREE_DEPTH, - MakeBuildingLeaf(20000.0, effect)); - + MakeBuildingLeaf(buildingRange, effect, (i != 2))); + // Transform building positions from the "geocentric" positions we // get from the scenery polys into the local Z-up coordinate // system. @@ -768,18 +773,18 @@ BuildingInstanceTransformer(transInv)); quadbuilding.buildQuadTree(rotatedBuildings.begin(), rotatedBuildings.end()); - for (size_t i = 0; i < quadbuilding.getRoot()->getNumChildren(); ++i) - group->addChild(quadbuilding.getRoot()->getChild(i)); + for (size_t j = 0; j < quadbuilding.getRoot()->getNumChildren(); ++j) + group->addChild(quadbuilding.getRoot()->getChild(j)); } - + return group; } - + // We may end up with a quadtree with many empty leaves. One might say // that we should avoid constructing the leaves in the first place, // but this node visitor tries to clean up after the fact. struct QuadTreeCleaner : public osg::NodeVisitor - { + { QuadTreeCleaner() : NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN) { } @@ -813,32 +818,32 @@ } } }; - + // This actually returns a MatrixTransform node. If we rotate the whole // forest into the local Z-up coordinate system we can reuse the // primitive building geometry for all the forests of the same type. - osg::Group* createRandomBuildings(SGBuildingBinList buildings, const osg::Matrix& transform, + osg::Group* createRandomBuildings(SGBuildingBinList& buildings, const osg::Matrix& transform, const SGReaderWriterOptions* options) { Matrix transInv = Matrix::inverse(transform); static Matrix ident; // Set up some shared structures. MatrixTransform* mt = new MatrixTransform(transform); + SGBuildingBinList::iterator i; - SGBuildingBin* bin = NULL; - - BOOST_FOREACH(bin, buildings) - { - numBuildings = numBuildings + bin->getNumBuildings(); + for (i = buildings.begin(); i != buildings.end(); ++i) { + SGBuildingBin* bin = *i; ref_ptr group = bin->createBuildingsGroup(transInv, options); - - for (size_t i = 0; i < group->getNumChildren(); ++i) - mt->addChild(group->getChild(i)); - - delete bin; - } - + + for (size_t j = 0; j < group->getNumChildren(); ++j) { + mt->addChild(group->getChild(j)); + } + + delete bin; + } + buildings.clear(); + QuadTreeCleaner cleaner; mt->accept(cleaner); return mt; diff -Nru simgear-2.10.0/simgear/scene/tgdb/SGBuildingBin.hxx simgear-3.0.0/simgear/scene/tgdb/SGBuildingBin.hxx --- simgear-2.10.0/simgear/scene/tgdb/SGBuildingBin.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/SGBuildingBin.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -45,7 +45,7 @@ #include #include -#define SG_BUILDING_QUAD_TREE_DEPTH 2 +#define SG_BUILDING_QUAD_TREE_DEPTH 4 #define SG_BUILDING_FADE_OUT_LEVELS 4 using namespace osg; @@ -56,9 +56,9 @@ public: // Number of buildings to auto-generate. Individual - // building instances are taken from this set. + // building instances are taken from this set. static const unsigned int BUILDING_SET_SIZE = 200; - + static const unsigned int QUADS_PER_BUILDING = 12; static const unsigned int VERTICES_PER_BUILDING = 4 * QUADS_PER_BUILDING; static const unsigned int VERTICES_PER_BUILDING_SET = BUILDING_SET_SIZE * VERTICES_PER_BUILDING; @@ -66,21 +66,21 @@ enum BuildingType { SMALL = 0, MEDIUM, - LARGE }; - + LARGE }; + private: struct Building { Building(BuildingType t, float w, float d, float h, int f, bool pitch) : - type(t), - width(w), - depth(d), - height(h), + type(t), + width(w), + depth(d), + height(h), floors(f), - pitched(pitch), + pitched(pitch), radius(std::max(d, 0.5f*w)) { } - + BuildingType type; float width; float depth; @@ -88,22 +88,22 @@ int floors; bool pitched; float radius; - + float getFootprint() { return radius; } }; - + // The set of buildings that are instantiated typedef std::vector BuildingList; BuildingList smallBuildings; BuildingList mediumBuildings; BuildingList largeBuildings; - - std::string material_name; - std::string texture; - std::string lightMap; - + + std::string* material_name; + std::string* texture; + std::string* lightMap; + // Fraction of buildings of this type float smallBuildingFraction; float mediumBuildingFraction; @@ -112,17 +112,20 @@ float smallBuildingMaxRadius; float mediumBuildingMaxRadius; float largeBuildingMaxRadius; - + // The maximum depth of each building type float smallBuildingMaxDepth; float mediumBuildingMaxDepth; float largeBuildingMaxDepth; - + + // Visibility range for buildings + float buildingRange; + // Shared geometries of the building set ref_ptr smallSharedGeometry; ref_ptr mediumSharedGeometry; ref_ptr largeSharedGeometry; - + struct BuildingInstance { BuildingInstance(SGVec3f p, float r, const BuildingList* bl, ref_ptr sg) : position(p), @@ -130,26 +133,26 @@ buildingList(bl), sharedGeometry(sg) { } - + BuildingInstance(SGVec3f p, BuildingInstance b) : position(p), rotation(b.rotation), buildingList(b.buildingList), sharedGeometry(b.sharedGeometry) - { } - + { } + SGVec3f position; float rotation; - + // References to allow the QuadTreeBuilder to work const BuildingList* buildingList; - ref_ptr sharedGeometry; - + ref_ptr sharedGeometry; + SGVec3f getPosition() { return position; } float getRotation() { return rotation; } - + float getDistSqr(SGVec3f p) { - return distSqr(p, position); + return distSqr(p, position); } const osg::Vec4f getColorValue() { @@ -158,65 +161,73 @@ }; // Information for an instance of a building - position and orientation - typedef std::vector BuildingInstanceList; + typedef std::vector BuildingInstanceList; BuildingInstanceList smallBuildingLocations; BuildingInstanceList mediumBuildingLocations; BuildingInstanceList largeBuildingLocations; - -public: + +public: SGBuildingBin(const SGMaterial *mat); - + ~SGBuildingBin() { - smallBuildings.clear(); + smallBuildings.clear(); mediumBuildings.clear(); largeBuildings.clear(); smallBuildingLocations.clear(); mediumBuildingLocations.clear(); largeBuildingLocations.clear(); } - + void insert(SGVec3f p, float r, BuildingType type); int getNumBuildings(); - + bool checkMinDist (SGVec3f p, float radius); - - std::string getMaterialName() { return material_name; } - + + std::string* getMaterialName() { return material_name; } + BuildingType getBuildingType(float roll); - + float getBuildingMaxRadius(BuildingType); float getBuildingMaxDepth(BuildingType); - + // Helper classes for creating the quad tree struct MakeBuildingLeaf { - MakeBuildingLeaf(float range, Effect* effect) : - _range(range), _effect(effect) {} - + MakeBuildingLeaf(float range, Effect* effect, bool fade) : + _range(range), _effect(effect), _fade_out(fade) {} + MakeBuildingLeaf(const MakeBuildingLeaf& rhs) : - _range(rhs._range), _effect(rhs._effect) + _range(rhs._range), _effect(rhs._effect), _fade_out(rhs._fade_out) {} LOD* operator() () const { LOD* result = new LOD; - - // Create a series of LOD nodes so trees cover decreases slightly - // gradually with distance from _range to 2*_range - for (float i = 0.0; i < SG_BUILDING_FADE_OUT_LEVELS; i++) - { + + if (_fade_out) { + // Create a series of LOD nodes so buidling cover decreases + // gradually with distance from _range to 2*_range + for (float i = 0.0; i < SG_BUILDING_FADE_OUT_LEVELS; i++) + { + EffectGeode* geode = new EffectGeode; + geode->setEffect(_effect.get()); + result->addChild(geode, 0, _range * (1.0 + i / (SG_BUILDING_FADE_OUT_LEVELS - 1.0))); + } + } else { + // No fade-out, so all are visible for 2X range EffectGeode* geode = new EffectGeode; geode->setEffect(_effect.get()); - result->addChild(geode, 0, _range * (1.0 + i / (SG_BUILDING_FADE_OUT_LEVELS - 1.0))); + result->addChild(geode, 0, 2.0 * _range); } return result; } - + float _range; ref_ptr _effect; + bool _fade_out; }; - + struct AddBuildingLeafObject { Geometry* createNewBuildingGeometryInstance(const BuildingInstance& building) const @@ -226,32 +237,32 @@ geom->setColorBinding(Geometry::BIND_PER_VERTEX); geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS)); return geom; - } - + } + void operator() (LOD* lod, const BuildingInstance& building) const { Geode* geode = static_cast(lod->getChild(int(building.position.x() * 10.0f) % lod->getNumChildren())); - unsigned int numDrawables = geode->getNumDrawables(); - + unsigned int numDrawables = geode->getNumDrawables(); + // Get the last geometry of to be added and check if there is space for // another building instance within it. This is done by checking // if the number of Color values matches the number of vertices. // The color array is used to store the position of a particular // instance. Geometry* geom; - + if (numDrawables == 0) { // Create a new copy of the shared geometry to instantiate geom = createNewBuildingGeometryInstance(building); geode->addDrawable(geom); } else { - geom = static_cast(geode->getDrawable(numDrawables - 1)); + geom = static_cast(geode->getDrawable(numDrawables - 1)); } - + // Check if this building is too close to any other others. DrawArrays* primSet = static_cast(geom->getPrimitiveSet(0)); Vec4Array* posArray = static_cast(geom->getColorArray()); - + // Now check if this geometry is full. if (posArray->size() >= static_cast(geom->getVertexArray())->size()) { // This particular geometry is full, so we generate another @@ -261,7 +272,7 @@ posArray = static_cast(geom->getColorArray()); SG_LOG(SG_TERRAIN, SG_DEBUG, "Added new geometry to building geod: " << geode->getNumDrawables()); } - + // We now have a geometry with space for this new building. // Set the position and rotation osg::Vec4f c = osg::Vec4f(toOsg(building.position), building.rotation); @@ -282,7 +293,7 @@ typedef QuadTreeBuilder BuildingGeometryQuadtree; - + struct BuildingInstanceTransformer { BuildingInstanceTransformer(Matrix& mat_) : mat(mat_) {} @@ -293,8 +304,8 @@ } Matrix mat; }; - - ref_ptr createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options); + + ref_ptr createBuildingsGroup(Matrix transInv, const SGReaderWriterOptions* options); }; @@ -302,7 +313,7 @@ typedef std::list SGBuildingBinList; -osg::Group* createRandomBuildings(SGBuildingBinList buildinglist, const osg::Matrix& transform, +osg::Group* createRandomBuildings(SGBuildingBinList& buildinglist, const osg::Matrix& transform, const SGReaderWriterOptions* options); } #endif diff -Nru simgear-2.10.0/simgear/scene/tgdb/SGOceanTile.cxx simgear-3.0.0/simgear/scene/tgdb/SGOceanTile.cxx --- simgear-2.10.0/simgear/scene/tgdb/SGOceanTile.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/SGOceanTile.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -282,7 +282,7 @@ double tex_width = 1000.0; // find Ocean material in the properties list - SGMaterial *mat = matlib->find( "Ocean" ); + SGMaterial *mat = matlib->findCached( "Ocean" ); if ( mat != NULL ) { // set the texture width and height values for this // material @@ -311,6 +311,7 @@ cl->push_back(osg::Vec4(1, 1, 1, 1)); osg::Geometry* geometry = new osg::Geometry; + geometry->setDataVariance(osg::Object::STATIC); geometry->setVertexArray(grid.vl); geometry->setNormalArray(grid.nl); geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); diff -Nru simgear-2.10.0/simgear/scene/tgdb/SGReaderWriterBTG.cxx simgear-3.0.0/simgear/scene/tgdb/SGReaderWriterBTG.cxx --- simgear-2.10.0/simgear/scene/tgdb/SGReaderWriterBTG.cxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/SGReaderWriterBTG.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -24,6 +24,7 @@ #include #include +#include #include "SGReaderWriterBTG.hxx" #include "obj.hxx" @@ -60,10 +61,17 @@ { const SGReaderWriterOptions* sgOptions; sgOptions = dynamic_cast(options); - osg::Node* result = SGLoadBTG(fileName, sgOptions); - if (!result) - return ReadResult::FILE_NOT_HANDLED; - + osg::Node* result = NULL; + try { + result = SGLoadBTG(fileName, sgOptions); + if (!result) + return ReadResult::FILE_NOT_HANDLED; + } catch (sg_exception& e) { + SG_LOG(SG_IO, SG_WARN, "error reading:" << fileName << ":" << + e.getFormattedMessage()); + return ReadResult::ERROR_IN_READING_FILE; + } + return result; } diff -Nru simgear-2.10.0/simgear/scene/tgdb/SGTexturedTriangleBin.hxx simgear-3.0.0/simgear/scene/tgdb/SGTexturedTriangleBin.hxx --- simgear-2.10.0/simgear/scene/tgdb/SGTexturedTriangleBin.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/SGTexturedTriangleBin.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -330,6 +330,7 @@ colors->push_back(osg::Vec4(1, 1, 1, 1)); osg::Geometry* geometry = new osg::Geometry; + geometry->setDataVariance(osg::Object::STATIC); geometry->setVertexArray(vertices); geometry->setNormalArray(normals); geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX); diff -Nru simgear-2.10.0/simgear/scene/tgdb/TreeBin.cxx simgear-3.0.0/simgear/scene/tgdb/TreeBin.cxx --- simgear-2.10.0/simgear/scene/tgdb/TreeBin.cxx 2013-01-28 17:02:15.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tgdb/TreeBin.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -138,8 +138,8 @@ float variety = mt_rand(&seed); t->push_back(Vec2(variety, 0.0f)); t->push_back(Vec2(variety + 1.0f, 0.0f)); - t->push_back(Vec2(variety + 1.0f, 1.0f)); - t->push_back(Vec2(variety, 1.0f)); + t->push_back(Vec2(variety + 1.0f, 0.234f)); + t->push_back(Vec2(variety, 0.234f)); } Geometry* result = new Geometry; result->setVertexArray(v); diff -Nru simgear-2.10.0/simgear/scene/tsync/terrasync.cxx simgear-3.0.0/simgear/scene/tsync/terrasync.cxx --- simgear-2.10.0/simgear/scene/tsync/terrasync.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tsync/terrasync.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -33,14 +33,12 @@ #endif #ifdef __MINGW32__ -#include -#include +# include +# include #elif defined(_MSC_VER) # include -# ifndef HAVE_SVN_CLIENT_H -# include -# include -# endif +# include +# include #endif #include // atoi() atof() abs() system() @@ -55,34 +53,19 @@ #include #include "terrasync.hxx" + #include #include #include #include #include +#include +#include +#include +#include +#include -#ifdef HAVE_SVN_CLIENT_H -# ifdef HAVE_LIBSVN_CLIENT_1 -# include -# include -# include -# include -# include -# else -# undef HAVE_SVN_CLIENT_H -# endif -#endif - -#ifdef HAVE_SVN_CLIENT_H - static const svn_version_checklist_t mysvn_checklist[] = { - { "svn_subr", svn_subr_version }, - { "svn_client", svn_client_version }, - { NULL, NULL } - }; - static const bool svn_built_in_available = true; -#else - static const bool svn_built_in_available = false; -#endif +static const bool svn_built_in_available = true; using namespace simgear; using namespace std; @@ -125,17 +108,98 @@ } /////////////////////////////////////////////////////////////////////////////// -// WaitingTile //////////////////////////////////////////////////////////////// +// SyncItem //////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -class WaitingTile +class SyncItem { public: - WaitingTile(string dir,bool refresh) : - _dir(dir), _refreshScenery(refresh) {} + enum Type + { + Stop = 0, ///< special item indicating to stop the SVNThread + Tile, + AirportData, + SharedModels, + AIData + }; + + enum Status + { + Invalid = 0, + Waiting, + Cached, ///< using already cached result + Updated, + NotFound, + Failed + }; + + SyncItem() : + _dir(), + _type(Stop), + _status(Invalid) + { + } + + SyncItem(string dir, Type ty) : + _dir(dir), + _type(ty), + _status(Waiting) + {} + string _dir; - bool _refreshScenery; + Type _type; + Status _status; +}; + +/////////////////////////////////////////////////////////////////////////////// + +/** + * @brief SyncSlot encapsulates a queue of sync items we will fetch + * serially. Multiple slots exist to sync different types of item in + * parallel. + */ +class SyncSlot +{ +public: + SyncSlot() : + isNewDirectory(false), + busy(false) + {} + + SyncItem currentItem; + bool isNewDirectory; + std::queue queue; + std::auto_ptr repository; + SGTimeStamp stamp; + bool busy; ///< is the slot working or idle + + unsigned int nextWarnTimeout; }; +static const int SYNC_SLOT_TILES = 0; ///< Terrain and Objects sync +static const int SYNC_SLOT_SHARED_DATA = 1; /// shared Models and Airport data +static const int SYNC_SLOT_AI_DATA = 2; /// AI traffic and models +static const unsigned int NUM_SYNC_SLOTS = 3; + +/** + * @brief translate a sync item type into one of the available slots. + * This provides the scheduling / balancing / prioritising between slots. + */ +static unsigned int syncSlotForType(SyncItem::Type ty) +{ + switch (ty) { + case SyncItem::Tile: return SYNC_SLOT_TILES; + case SyncItem::SharedModels: + case SyncItem::AirportData: + return SYNC_SLOT_SHARED_DATA; + case SyncItem::AIData: + return SYNC_SLOT_AI_DATA; + + default: + return SYNC_SLOT_SHARED_DATA; + } +} + + /////////////////////////////////////////////////////////////////////////////// // SGTerraSync::SvnThread ///////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// @@ -148,13 +212,15 @@ void stop(); bool start(); - bool isIdle() {return waitingTiles.empty();} - void request(const WaitingTile& dir) {waitingTiles.push_front(dir);} + bool isIdle() {return !_busy; } + void request(const SyncItem& dir) {waitingTiles.push_front(dir);} bool isDirty() { bool r = _is_dirty;_is_dirty = false;return r;} bool hasNewTiles() { return !_freshTiles.empty();} - WaitingTile getNewTile() { return _freshTiles.pop_front();} + SyncItem getNewTile() { return _freshTiles.pop_front();} void setSvnServer(string server) { _svn_server = stripPath(server);} + void setSvnDataServer(string server) { _svn_data_server = stripPath(server);} + void setExtSvnUtility(string svn_util) { _svn_command = simgear::strutils::strip(svn_util);} void setRsyncServer(string server) { _rsync_server = simgear::strutils::strip(server);} void setLocalDir(string dir) { _local_dir = stripPath(dir);} @@ -162,9 +228,9 @@ void setUseSvn(bool use_svn) { _use_svn = use_svn;} void setAllowedErrorCount(int errors) {_allowed_errors = errors;} -#ifdef HAVE_SVN_CLIENT_H - void setUseBuiltin(bool built_in) { _use_built_in = built_in;} -#endif + void setCachePath(const SGPath& p) {_persistentCachePath = p;} + void setCacheHits(unsigned int hits) {_cache_hits = hits;} + void setUseBuiltin(bool built_in) { _use_built_in = built_in;} volatile bool _active; volatile bool _running; @@ -175,44 +241,49 @@ volatile int _success_count; volatile int _consecutive_errors; volatile int _allowed_errors; - + volatile int _cache_hits; + volatile int _transfer_rate; + // kbytes, not bytes, because bytes might overflow 2^31 + volatile int _total_kb_downloaded; + private: virtual void run(); - bool syncTree(const char* dir, bool& isNewDirectory); - bool syncTreeExternal(const char* dir); + + // external model run and helpers + void runExternal(); + void syncPathExternal(const SyncItem& next); + bool runExternalSyncCommand(const char* dir); + + // internal mode run and helpers + void runInternal(); + void updateSyncSlot(SyncSlot& slot); -#ifdef HAVE_SVN_CLIENT_H - static int svnClientSetup(void); - bool syncTreeInternal(const char* dir); - - bool _use_built_in; - - // Things we need for doing subversion checkout - often - static apr_pool_t *_svn_pool; - static svn_client_ctx_t *_svn_ctx; - static svn_opt_revision_t *_svn_rev; - static svn_opt_revision_t *_svn_rev_peg; -#endif + // commond helpers between both internal and external models + + bool isPathCached(const SyncItem& next) const; + void initCompletedTilesPersistentCache(); + void writeCompletedTilesPersistentCache() const; + void updated(SyncItem item, bool isNewDirectory); + void fail(SyncItem failedItem); + + bool _use_built_in; + HTTP::Client _http; + SyncSlot _syncSlots[NUM_SYNC_SLOTS]; volatile bool _is_dirty; volatile bool _stop; - SGBlockingDeque waitingTiles; + SGBlockingDeque waitingTiles; CompletedTiles _completedTiles; - SGBlockingDeque _freshTiles; + SGBlockingDeque _freshTiles; bool _use_svn; string _svn_server; + string _svn_data_server; string _svn_command; string _rsync_server; string _local_dir; + SGPath _persistentCachePath; }; -#ifdef HAVE_SVN_CLIENT_H - apr_pool_t* SGTerraSync::SvnThread::_svn_pool = NULL; - svn_client_ctx_t* SGTerraSync::SvnThread::_svn_ctx = NULL; - svn_opt_revision_t* SGTerraSync::SvnThread::_svn_rev = NULL; - svn_opt_revision_t* SGTerraSync::SvnThread::_svn_rev_peg = NULL; -#endif - SGTerraSync::SvnThread::SvnThread() : _active(false), _running(false), @@ -223,21 +294,15 @@ _success_count(0), _consecutive_errors(0), _allowed_errors(6), -#ifdef HAVE_SVN_CLIENT_H + _cache_hits(0), + _transfer_rate(0), + _total_kb_downloaded(0), _use_built_in(true), -#endif _is_dirty(false), _stop(false), _use_svn(true) { -#ifdef HAVE_SVN_CLIENT_H - int errCode = SGTerraSync::SvnThread::svnClientSetup(); - if (errCode != EXIT_SUCCESS) - { - SG_LOG(SG_TERRAIN,SG_ALERT, - "Failed to initialize built-in SVN client, error = " << errCode); - } -#endif + _http.setUserAgent("terrascenery-" SG_STRINGIZE(SG_VERSION)); } void SGTerraSync::SvnThread::stop() @@ -250,7 +315,7 @@ // set stop flag and wake up the thread with an empty request _stop = true; - WaitingTile w("",false); + SyncItem w(string(), SyncItem::Stop); request(w); join(); _running = false; @@ -292,9 +357,7 @@ return false; } -#ifdef HAVE_SVN_CLIENT_H _use_svn |= _use_built_in; -#endif if ((_use_svn)&&(_svn_server=="")) { @@ -322,12 +385,10 @@ _running = true; string status; -#ifdef HAVE_SVN_CLIENT_H + if (_use_svn && _use_built_in) status = "Using built-in SVN support. "; - else -#endif - if (_use_svn) + else if (_use_svn) { status = "Using external SVN utility '"; status += _svn_command; @@ -349,114 +410,7 @@ return true; } -// sync one directory tree -bool SGTerraSync::SvnThread::syncTree(const char* dir, bool& isNewDirectory) -{ - int rc; - SGPath path( _local_dir ); - - path.append( dir ); - isNewDirectory = !path.exists(); - if (isNewDirectory) - { - rc = path.create_dir( 0755 ); - if (rc) - { - SG_LOG(SG_TERRAIN,SG_ALERT, - "Cannot create directory '" << dir << "', return code = " << rc ); - return false; - } - } - -#ifdef HAVE_SVN_CLIENT_H - if (_use_built_in) - return syncTreeInternal(dir); - else -#endif - { - return syncTreeExternal(dir); - } -} - - -#ifdef HAVE_SVN_CLIENT_H -bool SGTerraSync::SvnThread::syncTreeInternal(const char* dir) -{ - SG_LOG(SG_TERRAIN,SG_DEBUG, "Synchronizing scenery directory " << dir); - if (!_svn_pool) - { - SG_LOG(SG_TERRAIN,SG_ALERT, - "Built-in SVN client failed to initialize."); - return false; - } - - ostringstream command; - command << _svn_server << "/" << dir; - - ostringstream dest_base_dir; - dest_base_dir << _local_dir << "/" << dir; - - apr_pool_t *subpool = svn_pool_create(_svn_pool); - - svn_error_t *err = NULL; -#if (SVN_VER_MINOR >= 5) - err = svn_client_checkout3(NULL, - command.str().c_str(), - dest_base_dir.str().c_str(), - _svn_rev_peg, - _svn_rev, - svn_depth_infinity, - 0, // ignore-externals = false - 0, // allow unver obstructions = false - _svn_ctx, - subpool); -#else - // version 1.4 API - err = svn_client_checkout2(NULL, - command.str().c_str(), - dest_base_dir.str().c_str(), - _svn_rev_peg, - _svn_rev, - 1, // recurse=true - same as svn_depth_infinity for checkout3 above - 0, // ignore externals = false - _svn_ctx, - subpool); -#endif - - bool ReturnValue = true; - if (err) - { - // Report errors from the checkout attempt - if (err->apr_err == SVN_ERR_RA_ILLEGAL_URL) - { - // ignore errors when remote path doesn't exist (no scenery data for ocean areas) - } - else - { - SG_LOG(SG_TERRAIN,SG_ALERT, - "Failed to synchronize directory '" << dir << "', " << - err->message << " (code " << err->apr_err << ")."); - svn_error_clear(err); - // try to clean up - err = svn_client_cleanup(dest_base_dir.str().c_str(), - _svn_ctx,subpool); - if (!err) - { - SG_LOG(SG_TERRAIN,SG_ALERT, - "SVN repository cleanup successful for '" << dir << "'."); - } - ReturnValue = false; - } - } else - { - SG_LOG(SG_TERRAIN,SG_DEBUG, "Done with scenery directory " << dir); - } - svn_pool_destroy(subpool); - return ReturnValue; -} -#endif - -bool SGTerraSync::SvnThread::syncTreeExternal(const char* dir) +bool SGTerraSync::SvnThread::runExternalSyncCommand(const char* dir) { ostringstream buf; SGPath localPath( _local_dir ); @@ -513,49 +467,39 @@ void SGTerraSync::SvnThread::run() { _active = true; + initCompletedTilesPersistentCache(); + + + if (_use_built_in) { + runInternal(); + } else { + runExternal(); + } + + _active = false; + _running = false; + _is_dirty = true; +} + +void SGTerraSync::SvnThread::runExternal() +{ while (!_stop) { - WaitingTile next = waitingTiles.pop_front(); + SyncItem next = waitingTiles.pop_front(); if (_stop) break; - CompletedTiles::iterator ii = - _completedTiles.find( next._dir ); - time_t now = time(0); - if ((ii == _completedTiles.end())|| - (ii->second < now )) - { - bool isNewDirectory = false; - - _busy = true; - if (!syncTree(next._dir.c_str(),isNewDirectory)) - { - _consecutive_errors++; - _fail_count++; - _completedTiles[ next._dir ] = now + UpdateInterval::FailedAttempt; - } - else - { - _consecutive_errors = 0; - _success_count++; - SG_LOG(SG_TERRAIN,SG_INFO, - "Successfully synchronized directory '" << next._dir << "'"); - if (next._refreshScenery) - { - // updated a tile - _updated_tile_count++; - if (isNewDirectory) - { - // for now only report new directories to refresh display - // (i.e. only when ocean needs to be replaced with actual data) - _freshTiles.push_back(next); - _is_dirty = true; - } - } - _completedTiles[ next._dir ] = now + UpdateInterval::SuccessfulAttempt; - } - _busy = false; + if (isPathCached(next)) { + _cache_hits++; + SG_LOG(SG_TERRAIN, SG_DEBUG, + "Cache hit for: '" << next._dir << "'"); + next._status = SyncItem::Cached; + _freshTiles.push_back(next); + _is_dirty = true; + continue; } + + syncPathExternal(next); if ((_allowed_errors >= 0)&& (_consecutive_errors >= _allowed_errors)) @@ -563,163 +507,323 @@ _stalled = true; _stop = true; } + } // of thread running loop +} + +void SGTerraSync::SvnThread::syncPathExternal(const SyncItem& next) +{ + _busy = true; + SGPath path( _local_dir ); + path.append( next._dir ); + bool isNewDirectory = !path.exists(); + + try { + if (isNewDirectory) { + int rc = path.create_dir( 0755 ); + if (rc) { + SG_LOG(SG_TERRAIN,SG_ALERT, + "Cannot create directory '" << path << "', return code = " << rc ); + throw sg_exception("Cannot create directory for terrasync", path.str()); + } + } + + if (!runExternalSyncCommand(next._dir.c_str())) { + throw sg_exception("Running external sync command failed"); + } + } catch (sg_exception& e) { + fail(next); + _busy = false; + return; } + + updated(next, isNewDirectory); + _busy = false; +} - _active = false; - _running = false; - _is_dirty = true; +void SGTerraSync::SvnThread::updateSyncSlot(SyncSlot &slot) +{ + if (slot.repository.get()) { + if (slot.repository->isDoingSync()) { +#if 0 + if (slot.stamp.elapsedMSec() > slot.nextWarnTimeout) { + SG_LOG(SG_TERRAIN, SG_INFO, "sync taking a long time:" << slot.currentItem._dir << " taken " << slot.stamp.elapsedMSec()); + SG_LOG(SG_TERRAIN, SG_INFO, "HTTP status:" << _http.hasActiveRequests()); + slot.nextWarnTimeout += 10000; + } +#endif + return; // easy, still working + } + + // check result + SVNRepository::ResultCode res = slot.repository->failure(); + if (res == SVNRepository::SVN_ERROR_NOT_FOUND) { + // this is fine, but maybe we should use a different return code + // in the future to higher layers can distinguish this case + slot.currentItem._status = SyncItem::NotFound; + _freshTiles.push_back(slot.currentItem); + _is_dirty = true; + } else if (res != SVNRepository::SVN_NO_ERROR) { + fail(slot.currentItem); + } else { + updated(slot.currentItem, slot.isNewDirectory); + SG_LOG(SG_TERRAIN, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " finished (" + << slot.stamp.elapsedMSec() << " msec"); + } + + // whatever happened, we're done with this repository instance + slot.busy = false; + slot.repository.reset(); + } + + // init and start sync of the next repository + if (!slot.queue.empty()) { + slot.currentItem = slot.queue.front(); + slot.queue.pop(); + + SGPath path(_local_dir); + path.append(slot.currentItem._dir); + slot.isNewDirectory = !path.exists(); + if (slot.isNewDirectory) { + int rc = path.create_dir( 0755 ); + if (rc) { + SG_LOG(SG_TERRAIN,SG_ALERT, + "Cannot create directory '" << path << "', return code = " << rc ); + fail(slot.currentItem); + return; + } + } // of creating directory step + + string serverUrl(_svn_server); + if (slot.currentItem._type == SyncItem::AIData) { + serverUrl = _svn_data_server; + } + + slot.repository.reset(new SVNRepository(path, &_http)); + slot.repository->setBaseUrl(serverUrl + "/" + slot.currentItem._dir); + slot.repository->update(); + + slot.nextWarnTimeout = 20000; + slot.stamp.stamp(); + slot.busy = true; + SG_LOG(SG_TERRAIN, SG_DEBUG, "sync of " << slot.repository->baseUrl() << " started, queue size is " << slot.queue.size()); + } } -#ifdef HAVE_SVN_CLIENT_H -// Configure our subversion session -int SGTerraSync::SvnThread::svnClientSetup(void) -{ - // Are we already prepared? - if (_svn_pool) return EXIT_SUCCESS; - // No, so initialize svn internals generally - -#ifdef _MSC_VER - // there is a segfault when providing an error stream. - // Apparently, calling setvbuf with a nul buffer is - // not supported under msvc 7.1 ( code inside svn_cmdline_init ) - if (svn_cmdline_init("terrasync", 0) != EXIT_SUCCESS) - return EXIT_FAILURE; +void SGTerraSync::SvnThread::runInternal() +{ + while (!_stop) { + _http.update(100); + _transfer_rate = _http.transferRateBytesPerSec(); + // convert from bytes to kbytes + _total_kb_downloaded = static_cast(_http.totalBytesDownloaded() / 1024); + + if (_stop) + break; + + // drain the waiting tiles queue into the sync slot queues. + while (!waitingTiles.empty()) { + SyncItem next = waitingTiles.pop_front(); + if (isPathCached(next)) { + _cache_hits++; + SG_LOG(SG_TERRAIN, SG_DEBUG, "TerraSync Cache hit for: '" << next._dir << "'"); + next._status = SyncItem::Cached; + _freshTiles.push_back(next); + _is_dirty = true; + continue; + } - // revert locale setting - setlocale(LC_ALL,"C"); -#else - /* svn_cmdline_init configures the locale. Setup environment to ensure the - * default "C" locale remains active, since fgfs isn't locale aware - especially - * requires "." as decimal point in strings containing floating point varibales. */ - setenv("LC_ALL", "C", 1); + unsigned int slot = syncSlotForType(next._type); + _syncSlots[slot].queue.push(next); + } + + bool anySlotBusy = false; + // update each sync slot in turn + for (unsigned int slot=0; slot < NUM_SYNC_SLOTS; ++slot) { + updateSyncSlot(_syncSlots[slot]); + anySlotBusy |= _syncSlots[slot].busy; + } - if (svn_cmdline_init("terrasync", stderr) != EXIT_SUCCESS) - return EXIT_FAILURE; -#endif + _busy = anySlotBusy; + if (!anySlotBusy) { + // wait on the blocking deque here, otherwise we spin + // the loop very fast, since _http::update with no connections + // active returns immediately. + waitingTiles.waitOnNotEmpty(); + } + } // of thread running loop +} - apr_pool_t *pool = NULL; +bool SGTerraSync::SvnThread::isPathCached(const SyncItem& next) const +{ + CompletedTiles::const_iterator ii = _completedTiles.find( next._dir ); + if (ii == _completedTiles.end()) { + return false; + } - apr_allocator_t* allocator = NULL; - int aprErr = apr_allocator_create(&allocator); - if (aprErr != APR_SUCCESS) - return EXIT_FAILURE; - - apr_pool_create_ex(&pool, NULL /* parent pool */, NULL /* abort func */, allocator); - - svn_error_t *err = NULL; - SVN_VERSION_DEFINE(_svn_version); - err = svn_ver_check_list(&_svn_version, mysvn_checklist); - if (err) - return svn_cmdline_handle_exit_error(err, pool, "fgfs: "); - err = svn_ra_initialize(pool); - if (err) - return svn_cmdline_handle_exit_error(err, pool, "fgfs: "); - char *config_dir = NULL; - err = svn_config_ensure(config_dir, pool); - if (err) - return svn_cmdline_handle_exit_error(err, pool, "fgfs: "); - err = svn_client_create_context(&_svn_ctx, pool); - if (err) - return svn_cmdline_handle_exit_error(err, pool, "fgfs: "); - err = svn_config_get_config(&(_svn_ctx->config), - config_dir, pool); - if (err) - return svn_cmdline_handle_exit_error(err, pool, "fgfs: "); - svn_config_t *cfg; - cfg = ( svn_config_t*) apr_hash_get( - _svn_ctx->config, - SVN_CONFIG_CATEGORY_CONFIG, - APR_HASH_KEY_STRING); - if (err) - return svn_cmdline_handle_exit_error(err, pool, "fgfs: "); - - svn_auth_baton_t *ab=NULL; - -#if (SVN_VER_MINOR >= 6) - err = svn_cmdline_create_auth_baton (&ab, - TRUE, NULL, NULL, config_dir, TRUE, FALSE, cfg, - _svn_ctx->cancel_func, _svn_ctx->cancel_baton, pool); -#else - err = svn_cmdline_setup_auth_baton(&ab, - TRUE, NULL, NULL, config_dir, TRUE, cfg, - _svn_ctx->cancel_func, _svn_ctx->cancel_baton, pool); -#endif + // check if the path still physically exists + SGPath p(_local_dir); + p.append(next._dir); + if (!p.exists()) { + return false; + } + + time_t now = time(0); + return (ii->second > now); +} + +void SGTerraSync::SvnThread::fail(SyncItem failedItem) +{ + time_t now = time(0); + _consecutive_errors++; + _fail_count++; + failedItem._status = SyncItem::Failed; + _freshTiles.push_back(failedItem); + _completedTiles[ failedItem._dir ] = now + UpdateInterval::FailedAttempt; + _is_dirty = true; +} - if (err) - return svn_cmdline_handle_exit_error(err, pool, "fgfs: "); +void SGTerraSync::SvnThread::updated(SyncItem item, bool isNewDirectory) +{ + time_t now = time(0); + _consecutive_errors = 0; + _success_count++; + SG_LOG(SG_TERRAIN,SG_INFO, + "Successfully synchronized directory '" << item._dir << "'"); - _svn_ctx->auth_baton = ab; -#if (SVN_VER_MINOR >= 5) - _svn_ctx->conflict_func = NULL; - _svn_ctx->conflict_baton = NULL; -#endif + item._status = SyncItem::Updated; + if (item._type == SyncItem::Tile) { + _updated_tile_count++; + } - // Now our magic revisions - _svn_rev = (svn_opt_revision_t*) apr_palloc(pool, - sizeof(svn_opt_revision_t)); - if (!_svn_rev) - return EXIT_FAILURE; - _svn_rev_peg = (svn_opt_revision_t*) apr_palloc(pool, - sizeof(svn_opt_revision_t)); - if (!_svn_rev_peg) - return EXIT_FAILURE; - _svn_rev->kind = svn_opt_revision_head; - _svn_rev_peg->kind = svn_opt_revision_unspecified; - // Success if we got this far - _svn_pool = pool; - return EXIT_SUCCESS; + _freshTiles.push_back(item); + _completedTiles[ item._dir ] = now + UpdateInterval::SuccessfulAttempt; + _is_dirty = true; + writeCompletedTilesPersistentCache(); +} + +void SGTerraSync::SvnThread::initCompletedTilesPersistentCache() +{ + if (!_persistentCachePath.exists()) { + return; + } + + SGPropertyNode_ptr cacheRoot(new SGPropertyNode); + time_t now = time(0); + + try { + readProperties(_persistentCachePath.str(), cacheRoot); + } catch (sg_exception& e) { + SG_LOG(SG_TERRAIN, SG_INFO, "corrupted persistent cache, discarding"); + return; + } + + for (int i=0; inChildren(); ++i) { + SGPropertyNode* entry = cacheRoot->getChild(i); + string tileName = entry->getStringValue("path"); + time_t stamp = entry->getIntValue("stamp"); + if (stamp < now) { + continue; + } + + _completedTiles[tileName] = stamp; + } +} + +void SGTerraSync::SvnThread::writeCompletedTilesPersistentCache() const +{ + // cache is disabled + if (_persistentCachePath.isNull()) { + return; + } + + std::ofstream f(_persistentCachePath.c_str(), std::ios::trunc); + if (!f.is_open()) { + return; + } + + SGPropertyNode_ptr cacheRoot(new SGPropertyNode); + CompletedTiles::const_iterator it = _completedTiles.begin(); + for (; it != _completedTiles.end(); ++it) { + SGPropertyNode* entry = cacheRoot->addChild("entry"); + entry->setStringValue("path", it->first); + entry->setIntValue("stamp", it->second); + } + + writeProperties(f, cacheRoot, true /* write_all */); + f.close(); } -#endif /////////////////////////////////////////////////////////////////////////////// // SGTerraSync //////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// -SGTerraSync::SGTerraSync(SGPropertyNode_ptr root) : +SGTerraSync::SGTerraSync() : _svnThread(NULL), last_lat(NOWHERE), last_lon(NOWHERE), - _terraRoot(root->getNode("/sim/terrasync",true)), - _refreshCb(NULL), - _userCbData(NULL) + _bound(false), + _inited(false) { _svnThread = new SvnThread(); + _log = new BufferedLogCallback(SG_TERRAIN, SG_INFO); + _log->truncateAt(255); + + sglog().addCallback(_log); } SGTerraSync::~SGTerraSync() { - _tiedProperties.Untie(); delete _svnThread; _svnThread = NULL; + sglog().removeCallback(_log); + delete _log; + _tiedProperties.Untie(); +} + +void SGTerraSync::setRoot(SGPropertyNode_ptr root) +{ + _terraRoot = root->getNode("/sim/terrasync",true); } void SGTerraSync::init() { - _refreshDisplay = _terraRoot->getNode("refresh-display",true); + if (_inited) { + return; + } + + _inited = true; + + assert(_terraRoot); _terraRoot->setBoolValue("built-in-svn-available",svn_built_in_available); + reinit(); } +void SGTerraSync::shutdown() +{ + _svnThread->stop(); +} + void SGTerraSync::reinit() { // do not reinit when enabled and we're already up and running if ((_terraRoot->getBoolValue("enabled",false))&& (_svnThread->_active && _svnThread->_running)) + { return; - + } + _svnThread->stop(); if (_terraRoot->getBoolValue("enabled",false)) { _svnThread->setSvnServer(_terraRoot->getStringValue("svn-server","")); + _svnThread->setSvnDataServer(_terraRoot->getStringValue("svn-data-server","")); _svnThread->setRsyncServer(_terraRoot->getStringValue("rsync-server","")); _svnThread->setLocalDir(_terraRoot->getStringValue("scenery-dir","")); _svnThread->setAllowedErrorCount(_terraRoot->getIntValue("max-errors",5)); - - #ifdef HAVE_SVN_CLIENT_H _svnThread->setUseBuiltin(_terraRoot->getBoolValue("use-built-in-svn",true)); - #else - _terraRoot->setBoolValue("use-built-in-svn",false); - #endif + _svnThread->setCachePath(SGPath(_terraRoot->getStringValue("cache-path",""))); + _svnThread->setCacheHits(_terraRoot->getIntValue("cache-hit", 0)); _svnThread->setUseSvn(_terraRoot->getBoolValue("use-svn",true)); _svnThread->setExtSvnUtility(_terraRoot->getStringValue("ext-svn-utility","svn")); @@ -743,11 +847,23 @@ void SGTerraSync::bind() { + if (_bound) { + return; + } + + _bound = true; _tiedProperties.Tie( _terraRoot->getNode("busy", true), (bool*) &_svnThread->_busy ); _tiedProperties.Tie( _terraRoot->getNode("active", true), (bool*) &_svnThread->_active ); _tiedProperties.Tie( _terraRoot->getNode("update-count", true), (int*) &_svnThread->_success_count ); _tiedProperties.Tie( _terraRoot->getNode("error-count", true), (int*) &_svnThread->_fail_count ); _tiedProperties.Tie( _terraRoot->getNode("tile-count", true), (int*) &_svnThread->_updated_tile_count ); + _tiedProperties.Tie( _terraRoot->getNode("cache-hits", true), (int*) &_svnThread->_cache_hits ); + _tiedProperties.Tie( _terraRoot->getNode("transfer-rate-bytes-sec", true), (int*) &_svnThread->_transfer_rate ); + + // use kbytes here because propety doesn't support 64-bit and we might conceivably + // download more than 2G in a single session + _tiedProperties.Tie( _terraRoot->getNode("downloaded-kbytes", true), (int*) &_svnThread->_total_kb_downloaded ); + _terraRoot->getNode("busy", true)->setAttribute(SGPropertyNode::WRITE,false); _terraRoot->getNode("active", true)->setAttribute(SGPropertyNode::WRITE,false); _terraRoot->getNode("update-count", true)->setAttribute(SGPropertyNode::WRITE,false); @@ -765,6 +881,12 @@ { _svnThread->stop(); _tiedProperties.Untie(); + _bound = false; + _inited = false; + + _terraRoot.clear(); + _stalledNode.clear(); + _cacheHits.clear(); } void SGTerraSync::update(double) @@ -788,51 +910,19 @@ _stalledNode->setBoolValue(_svnThread->_stalled); } - if (!_refreshDisplay->getBoolValue()) - return; - while (_svnThread->hasNewTiles()) { - WaitingTile next = _svnThread->getNewTile(); - if (next._refreshScenery) - { - refreshScenery(_svnThread->getLocalDir(),next._dir); - } - } - } -} - -void SGTerraSync::refreshScenery(SGPath path,const string& relativeDir) -{ - // find tiles to be refreshed - if (_refreshCb) - { - path.append(relativeDir); - if (path.exists()) - { - simgear::Dir dir(path); - //TODO need to be smarter here. only update tiles which actually - // changed recently. May also be possible to use information from the - // built-in SVN client directly (instead of checking directory contents). - PathList tileList = dir.children(simgear::Dir::TYPE_FILE, ".stg"); - for (unsigned int i=0; igetNewTile(); + + if ((next._type == SyncItem::Tile) || (next._type == SyncItem::AIData)) { + _activeTileDirs.erase(next._dir); } - } + } // of freshly synced items } } bool SGTerraSync::isIdle() {return _svnThread->isIdle();} -void SGTerraSync::setTileRefreshCb(SGTerraSyncCallback refreshCb, void* userCbData) -{ - _refreshCb = refreshCb; - _userCbData = userCbData; -} - void SGTerraSync::syncAirportsModels() { static const char* bounds = "MZAJKL"; // airport sync order: K-L, A-J, M-Z @@ -843,11 +933,12 @@ { ostringstream dir; dir << "Airports/" << synced_other; - WaitingTile w(dir.str(),false); + SyncItem w(dir.str(), SyncItem::AirportData); _svnThread->request( w ); } } - WaitingTile w("Models",false); + + SyncItem w("Models", SyncItem::SharedModels); _svnThread->request( w ); } @@ -884,17 +975,27 @@ EW = 'e'; } - const char* terrainobjects[3] = { "Terrain", "Objects", 0 }; - bool refresh=true; + ostringstream dir; + dir << setfill('0') + << EW << setw(3) << abs(baselon) << NS << setw(2) << abs(baselat) << "/" + << EW << setw(3) << abs(lon) << NS << setw(2) << abs(lat); + + syncAreaByPath(dir.str()); +} + +void SGTerraSync::syncAreaByPath(const std::string& aPath) +{ + const char* terrainobjects[3] = { "Terrain/", "Objects/", 0 }; for (const char** tree = &terrainobjects[0]; *tree; tree++) { - ostringstream dir; - dir << *tree << "/" << setfill('0') - << EW << setw(3) << abs(baselon) << NS << setw(2) << abs(baselat) << "/" - << EW << setw(3) << abs(lon) << NS << setw(2) << abs(lat); - WaitingTile w(dir.str(),refresh); + std::string dir = string(*tree) + aPath; + if (_activeTileDirs.find(dir) != _activeTileDirs.end()) { + continue; + } + + _activeTileDirs.insert(dir); + SyncItem w(dir, SyncItem::Tile); _svnThread->request( w ); - refresh=false; } } @@ -902,6 +1003,7 @@ void SGTerraSync::syncAreas( int lat, int lon, int lat_dir, int lon_dir ) { if ( lat_dir == 0 && lon_dir == 0 ) { + // do surrounding 8 1x1 degree areas. for ( int i = lat - 1; i <= lat + 1; ++i ) { for ( int j = lon - 1; j <= lon + 1; ++j ) { @@ -927,6 +1029,12 @@ syncArea( lat, lon ); } +bool SGTerraSync::scheduleTile(const SGBucket& bucket) +{ + std::string basePath = bucket.gen_base_path(); + syncAreaByPath(basePath); + return true; +} bool SGTerraSync::schedulePosition(int lat, int lon) { @@ -937,8 +1045,6 @@ { if (_svnThread->_running) { - SG_LOG(SG_TERRAIN,SG_DEBUG, "Requesting scenery update for position " << - lat << "," << lon); int lat_dir=0; int lon_dir=0; if ( last_lat != NOWHERE && last_lon != NOWHERE ) @@ -976,3 +1082,46 @@ return Ok; } + +void SGTerraSync::reposition() +{ + last_lat = last_lon = NOWHERE; +} + +bool SGTerraSync::isTileDirPending(const std::string& sceneryDir) const +{ + if (!_svnThread->_running) { + return false; + } + + const char* terrainobjects[3] = { "Terrain/", "Objects/", 0 }; + for (const char** tree = &terrainobjects[0]; *tree; tree++) { + string s = *tree + sceneryDir; + if (_activeTileDirs.find(s) != _activeTileDirs.end()) { + return true; + } + } + + return false; +} + +void SGTerraSync::scheduleDataDir(const std::string& dataDir) +{ + if (_activeTileDirs.find(dataDir) != _activeTileDirs.end()) { + return; + } + + _activeTileDirs.insert(dataDir); + SyncItem w(dataDir, SyncItem::AIData); + _svnThread->request( w ); + +} + +bool SGTerraSync::isDataDirPending(const std::string& dataDir) const +{ + if (!_svnThread->_running) { + return false; + } + + return (_activeTileDirs.find(dataDir) != _activeTileDirs.end()); +} diff -Nru simgear-2.10.0/simgear/scene/tsync/terrasync.hxx simgear-3.0.0/simgear/scene/tsync/terrasync.hxx --- simgear-2.10.0/simgear/scene/tsync/terrasync.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/tsync/terrasync.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -21,40 +21,71 @@ #ifndef TERRASYNC_HXX_ #define TERRASYNC_HXX_ +#include + #include #include #include class SGPath; +class SGBucket; namespace simgear { const int NOWHERE = -9999; -typedef void (*SGTerraSyncCallback)(void* userData, long tileIndex); +class BufferedLogCallback; class SGTerraSync : public SGSubsystem { public: - SGTerraSync(SGPropertyNode_ptr root); + SGTerraSync(); virtual ~SGTerraSync(); - virtual void init(); + + virtual void init(); + virtual void shutdown(); virtual void reinit(); virtual void bind(); virtual void unbind(); virtual void update(double); + /// notify terrasync that the sim was repositioned, as opposed to + /// us travelling in a direction. Avoid last_lat / last_lon blocking + /// certain tiles when we reposition. + void reposition(); + bool isIdle(); bool schedulePosition(int lat, int lon); - void setTileRefreshCb(SGTerraSyncCallback refreshCb, void* userData = NULL); - + + bool scheduleTile(const SGBucket& bucket); + + void setRoot(SGPropertyNode_ptr root); + + /// retrive the associated log object, for displaying log + /// output somewhere (a UI, presumably) + BufferedLogCallback* log() const + { return _log; } + + /** + * Test if a scenery directory is queued or actively syncing. + * File path is the tile name, eg 'e001n52' or 'w003n56'. Will return true + * if either the Terrain or Objects variant is being synced. + * + */ + bool isTileDirPending(const std::string& sceneryDir) const; + + + void scheduleDataDir(const std::string& dataDir); + + bool isDataDirPending(const std::string& dataDir) const; protected: void syncAirportsModels(); void syncArea(int lat, int lon); void syncAreas(int lat, int lon, int lat_dir, int lon_dir); - void refreshScenery(SGPath path,const std::string& relativeDir); + void syncAreaByPath(const std::string& aPath); + class SvnThread; private: @@ -62,11 +93,20 @@ int last_lat; int last_lon; SGPropertyNode_ptr _terraRoot; - SGPropertyNode_ptr _refreshDisplay; SGPropertyNode_ptr _stalledNode; - SGTerraSyncCallback _refreshCb; - void* _userCbData; + SGPropertyNode_ptr _cacheHits; + + // we manually bind+init TerraSync during early startup + // to get better overlap of slow operations (Shared Models sync + // and nav-cache rebuild). As a result we need to track the bind/init + // state explicitly to avoid duplicate calls. + bool _bound, _inited; + simgear::TiedPropertyList _tiedProperties; + BufferedLogCallback* _log; + + typedef std::set string_set; + string_set _activeTileDirs; }; } diff -Nru simgear-2.10.0/simgear/scene/util/CMakeLists.txt simgear-3.0.0/simgear/scene/util/CMakeLists.txt --- simgear-2.10.0/simgear/scene/util/CMakeLists.txt 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/util/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -1,11 +1,13 @@ include (SimGearComponent) -set(HEADERS +set(HEADERS + ColorInterpolator.hxx CopyOp.hxx DeletionManager.hxx NodeAndDrawableVisitor.hxx Noise.hxx OptionsReadFileCallback.hxx + OsgDebug.hxx OsgMath.hxx OsgSingleton.hxx parse_color.hxx @@ -29,12 +31,14 @@ project.hxx ) -set(SOURCES +set(SOURCES + ColorInterpolator.cxx CopyOp.cxx DeletionManager.cxx NodeAndDrawableVisitor.cxx Noise.cxx OptionsReadFileCallback.cxx + OsgDebug.cxx parse_color.cxx PrimitiveUtils.cxx QuadTreeBuilder.cxx @@ -53,7 +57,9 @@ simgear_scene_component(util scene/util "${SOURCES}" "${HEADERS}") if(ENABLE_TESTS) + add_executable(test_parse_color parse_color_test.cxx ) -add_test(test_parse_color ${EXECUTABLE_OUTPUT_PATH}/test_parse_color) -target_link_libraries(test_parse_color SimGearScene) +add_test(parse_color ${EXECUTABLE_OUTPUT_PATH}/test_parse_color) +target_link_libraries(test_parse_color ${TEST_LIBS}) + endif(ENABLE_TESTS) diff -Nru simgear-2.10.0/simgear/scene/util/ColorInterpolator.cxx simgear-3.0.0/simgear/scene/util/ColorInterpolator.cxx --- simgear-2.10.0/simgear/scene/util/ColorInterpolator.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/util/ColorInterpolator.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,74 @@ +// Adapter for interpolating string properties representing CSS colors. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "ColorInterpolator.hxx" +#include "parse_color.hxx" + +#include + +namespace simgear +{ + + //---------------------------------------------------------------------------- + void ColorInterpolator::setTarget(const SGPropertyNode& target) + { + if( !parseColor(target.getStringValue(), _color_end) ) + SG_LOG + ( + SG_GENERAL, SG_WARN, "ColorInterpolator: failed to parse end color." + ); + } + + //---------------------------------------------------------------------------- + void ColorInterpolator::init(const SGPropertyNode& prop) + { + osg::Vec4 color_start; + if( !parseColor(prop.getStringValue(), color_start) ) + // If unable to get current color, immediately change to target color + color_start = _color_end; + + _color_diff = _color_end - color_start; + } + + //---------------------------------------------------------------------------- + void ColorInterpolator::write(SGPropertyNode& prop, double t) + { + osg::Vec4 color_cur = _color_end - _color_diff * (1 - t); + bool has_alpha = color_cur.a() < 0.999; + + std::ostringstream strm; + strm << (has_alpha ? "rgba(" : "rgb("); + + // r, g, b (every component in [0, 255]) + for(size_t i = 0; i < 3; ++i) + { + if( i > 0 ) + strm << ','; + strm << static_cast(color_cur._v[i] * 255); + } + + // Write alpha if a < 1 (alpha is in [0, 1]) + if( has_alpha ) + strm << ',' << color_cur.a(); + + strm << ')'; + + prop.setStringValue(strm.str()); + } + +} // namespace simgear diff -Nru simgear-2.10.0/simgear/scene/util/ColorInterpolator.hxx simgear-3.0.0/simgear/scene/util/ColorInterpolator.hxx --- simgear-2.10.0/simgear/scene/util/ColorInterpolator.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/util/ColorInterpolator.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,49 @@ +// Adapter for interpolating string properties representing CSS colors. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_COLOR_INTERPOLATOR_HXX_ +#define SG_COLOR_INTERPOLATOR_HXX_ + +#include + +#include +#include + +namespace simgear +{ + + /** + * Interpolate a string property containing containing a %CSS color. + */ + class ColorInterpolator: + public PropertyInterpolator + { + protected: + osg::Vec4 _color_end, + _color_diff; + + virtual void setTarget(const SGPropertyNode& target); + virtual void init(const SGPropertyNode& prop); + virtual void write(SGPropertyNode& prop, double t); + + + }; + +} // namespace simgear + +#endif /* SG_COLOR_INTERPOLATOR_HXX_ */ diff -Nru simgear-2.10.0/simgear/scene/util/DeletionManager.cxx simgear-3.0.0/simgear/scene/util/DeletionManager.cxx --- simgear-2.10.0/simgear/scene/util/DeletionManager.cxx 2013-01-28 17:02:15.000000000 +0000 +++ simgear-3.0.0/simgear/scene/util/DeletionManager.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -45,6 +45,11 @@ _staleObjects.push_back(obj); } +void DeletionManager::uninstall(Node* node) +{ + node->removeEventCallback(instance()); +} + void DeletionManager::install(Node* node) { node->addEventCallback(instance()); diff -Nru simgear-2.10.0/simgear/scene/util/DeletionManager.hxx simgear-3.0.0/simgear/scene/util/DeletionManager.hxx --- simgear-2.10.0/simgear/scene/util/DeletionManager.hxx 2013-01-28 17:02:15.000000000 +0000 +++ simgear-3.0.0/simgear/scene/util/DeletionManager.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -38,6 +38,7 @@ osg::Object* object, osg::NodeVisitor* nv); void addStaleObject(osg::Referenced* obj); static void install(osg::Node* node); + static void uninstall(osg::Node* node); static DeletionManager* instance(); protected: OpenThreads::Mutex _mutex; diff -Nru simgear-2.10.0/simgear/scene/util/OsgDebug.cxx simgear-3.0.0/simgear/scene/util/OsgDebug.cxx --- simgear-2.10.0/simgear/scene/util/OsgDebug.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/util/OsgDebug.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,49 @@ +// Helper for OSG related debugging +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#include "OsgDebug.hxx" +#include + +namespace simgear +{ + + //---------------------------------------------------------------------------- + std::string getNodePathString(const osg::Node* node) + { + if( !node ) + return "(nullptr)"; + + std::string str; + const osg::NodePathList& paths = node->getParentalNodePaths(); + for(size_t i = 0; i < paths.size(); ++i) + { + if( !str.empty() ) + str += ":"; + + const osg::NodePath& path = paths.at(i); + for(size_t j = 0; j < path.size(); ++j) + { + const osg::Node* node = path[j]; + str += "/'" + node->getName() + "'"; + } + } + + return str; + } + +} // namespace simgear diff -Nru simgear-2.10.0/simgear/scene/util/OsgDebug.hxx simgear-3.0.0/simgear/scene/util/OsgDebug.hxx --- simgear-2.10.0/simgear/scene/util/OsgDebug.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/scene/util/OsgDebug.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,36 @@ +///@file Helper for OSG related debugging +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef OSGDEBUG_HXX_ +#define OSGDEBUG_HXX_ + +#include + +namespace osg { class Node; } +namespace simgear +{ + + /** + * Get parent path(s) of scene graph node as string. + */ + std::string getNodePathString(const osg::Node* node); + +} // namespace simgear + + +#endif /* OSGDEBUG_HXX_ */ diff -Nru simgear-2.10.0/simgear/scene/util/parse_color.cxx simgear-3.0.0/simgear/scene/util/parse_color.cxx --- simgear-2.10.0/simgear/scene/util/parse_color.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/util/parse_color.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -23,6 +23,8 @@ #include #include +#include + namespace simgear { @@ -81,7 +83,38 @@ } } else - return false; + { + // Basic color keywords + // http://www.w3.org/TR/css3-color/#html4 + typedef std::map ColorMap; + static ColorMap colors; + if( colors.empty() ) + { + colors["red" ] = osg::Vec4(1, 0, 0, 1); + colors["black" ] = osg::Vec4(0, 0, 0, 1); + colors["silver" ] = osg::Vec4(0.75, 0.75, 0.75, 1); + colors["gray" ] = osg::Vec4(0.5, 0.5, 0.5, 1); + colors["white" ] = osg::Vec4(1, 1, 1, 1); + colors["maroon" ] = osg::Vec4(0.5, 0, 0, 1); + colors["red" ] = osg::Vec4(1, 0, 0, 1); + colors["purple" ] = osg::Vec4(0.5, 0, 0.5, 1); + colors["fuchsia"] = osg::Vec4(1, 0, 1, 1); + colors["green" ] = osg::Vec4(0, 0.5, 0, 1); + colors["lime" ] = osg::Vec4(0, 1, 0, 1); + colors["olive" ] = osg::Vec4(0.5, 0.5, 0, 1); + colors["yellow" ] = osg::Vec4(1, 1, 0, 1); + colors["navy" ] = osg::Vec4(0, 0, 0.5, 1); + colors["blue" ] = osg::Vec4(0, 0, 1, 1); + colors["teal" ] = osg::Vec4(0, 0.5, 0.5, 1); + colors["aqua" ] = osg::Vec4(0, 1, 1, 1); + } + ColorMap::const_iterator it = colors.find(str); + if( it == colors.end() ) + return false; + + result = it->second; + return true; + } result = color; return true; diff -Nru simgear-2.10.0/simgear/scene/util/parse_color_test.cxx simgear-3.0.0/simgear/scene/util/parse_color_test.cxx --- simgear-2.10.0/simgear/scene/util/parse_color_test.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/scene/util/parse_color_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -1,26 +1,33 @@ #include #include "parse_color.hxx" +#include "ColorInterpolator.hxx" +#include #include #define COMPARE(a, b) \ if( (a) != (b) ) \ { \ - std::cerr << "failed:" << #a << " != " << #b << std::endl; \ + std::cerr << "line " << __LINE__ << ": failed: "\ + << #a << " != " << #b << std::endl; \ return 1; \ } #define VERIFY(a) \ if( !(a) ) \ { \ - std::cerr << "failed:" << #a << std::endl; \ + std::cerr << "line " << __LINE__ << ": failed: "\ + << #a << std::endl; \ return 1; \ } #define VERIFY_COLOR(str, r, g, b, a) \ VERIFY(simgear::parseColor(str, color)) \ COMPARE(color, osg::Vec4(r, g, b, a)) + +#define VERIFY_NODE_STR(node, str) \ + COMPARE(node.getStringValue(), std::string(str)) int main (int ac, char ** av) { @@ -30,6 +37,36 @@ VERIFY_COLOR("#0000ff", 0,0,1,1); VERIFY_COLOR("rgb( 255,\t127.5,0)", 1, 0.5, 0, 1); VERIFY_COLOR("rgba(255, 127.5,0, 0.5)", 1, 0.5, 0, 0.5); + + SGPropertyNode color_node, color_arg; + color_arg.setStringValue("#000000"); + + simgear::PropertyInterpolator* interp = new simgear::ColorInterpolator; + interp->reset(color_arg); + + interp->update(color_node, 0.5); // with no color it should immediately set to the target + VERIFY_NODE_STR(color_node, "rgb(0,0,0)"); + + color_arg.setStringValue("rgba(255,0,0,0.5)"); + interp->reset(color_arg); + + interp->update(color_node, 0.5); + VERIFY_NODE_STR(color_node, "rgba(127,0,0,0.75)"); + + interp->update(color_node, 0.5); + VERIFY_NODE_STR(color_node, "rgba(255,0,0,0.5)"); + + // Animation has already completed and therefore should be reset and start a + // new animation starting with the current value of the animation. As this + // is already the same as the target value, nothing should change. + interp->update(color_node, 0.5); + VERIFY_NODE_STR(color_node, "rgba(255,0,0,0.5)"); + + color_arg.setStringValue("#00ff00"); + interp->reset(color_arg); + interp->update(color_node, 1.0); + VERIFY_NODE_STR(color_node, "rgb(0,255,0)"); + std::cout << "all tests passed successfully!" << std::endl; return 0; } diff -Nru simgear-2.10.0/simgear/scene/util/SGPickCallback.hxx simgear-3.0.0/simgear/scene/util/SGPickCallback.hxx --- simgear-2.10.0/simgear/scene/util/SGPickCallback.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/scene/util/SGPickCallback.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -22,10 +22,14 @@ #ifndef SG_SCENE_PICKCALLBACK_HXX #define SG_SCENE_PICKCALLBACK_HXX +#include + #include #include #include +namespace osgGA { class GUIEventAdapter; } + // Used to implement scenery interaction. // The interface is still under development class SGPickCallback : public SGReferenced { @@ -33,12 +37,14 @@ enum Priority { PriorityGUI = 0, PriorityPanel = 1, - PriorityOther = 2 + PriorityOther = 2, + PriorityScenery = 3 }; struct Info { SGVec3d wgs84; SGVec3d local; + SGVec2d uv; }; SGPickCallback(Priority priority = PriorityOther) : @@ -46,15 +52,59 @@ { } virtual ~SGPickCallback() {} - virtual bool buttonPressed(int button, const Info& info) + + // TODO maybe better provide a single callback to handle all events + virtual bool buttonPressed( int button, + const osgGA::GUIEventAdapter& ea, + const Info& info ) { return false; } - virtual void update(double dt) + + virtual void update(double dt, int keyModState) { } - virtual void buttonReleased(void) + + /** + * @param info Can be null if no info is available (eg. mouse not over 3d + * object anymore) + */ + virtual void buttonReleased( int keyModState, + const osgGA::GUIEventAdapter& ea, + const Info* info ) + { } + + /** + * @param info Can be null if no info is available (eg. mouse not over 3d + * object anymore) + */ + virtual void mouseMoved( const osgGA::GUIEventAdapter& ea, + const Info* info ) { } - Priority getPriority() const + /** + * The mouse is not hovering anymore over the element. + */ + virtual void mouseLeave(const osg::Vec2d& windowPos) + { } + + virtual bool hover( const osg::Vec2d& windowPos, + const Info& info ) + { return false; } + + virtual Priority getPriority() const { return _priority; } + + /** + * retrieve the name of the cursor to user when hovering this pickable + * object. Mapping is undefined, since SimGear doesn't know about cursors. + */ + virtual std::string getCursor() const + { return std::string(); } + + /** + * Whether the uv coordinates of the picking action should be calculated upon + * an intersection. + */ + virtual bool needsUV() const + { return false; } private: Priority _priority; diff -Nru simgear-2.10.0/simgear/scene/util/SGReaderWriterOptions.hxx simgear-3.0.0/simgear/scene/util/SGReaderWriterOptions.hxx --- simgear-2.10.0/simgear/scene/util/SGReaderWriterOptions.hxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/scene/util/SGReaderWriterOptions.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -22,10 +22,12 @@ #include #include +#include + #include class SGPropertyNode; -class SGMaterialLib; + namespace simgear { @@ -70,7 +72,7 @@ void setPropertyNode(const SGSharedPtr& propertyNode) { _propertyNode = propertyNode; } - SGMaterialLib* getMaterialLib() const + SGMaterialLibPtr getMaterialLib() const { return _materialLib; } void setMaterialLib(SGMaterialLib* materialLib) { _materialLib = materialLib; } @@ -100,7 +102,7 @@ private: SGSharedPtr _propertyNode; - SGMaterialLib* _materialLib; + SGSharedPtr _materialLib; osg::Node *(*_load_panel)(SGPropertyNode *); osg::ref_ptr _model_data; bool _instantiateEffects; diff -Nru simgear-2.10.0/simgear/screen/screen-dump.cxx simgear-3.0.0/simgear/screen/screen-dump.cxx --- simgear-2.10.0/simgear/screen/screen-dump.cxx 2012-01-17 20:33:53.000000000 +0000 +++ simgear-3.0.0/simgear/screen/screen-dump.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -23,14 +23,6 @@ # include #endif -#ifdef WIN32 -# include -#endif - -#include -#include -#include - #include #include @@ -39,48 +31,6 @@ #include "screen-dump.hxx" -#define RGB3 3 // 3 bytes of color info per pixel -#define RGBA 4 // 4 bytes of color+alpha info - -bool sg_glWritePPMFile(const char *filename, GLubyte *buffer, int win_width, int win_height, int mode) -{ - int i, j, k, q; - unsigned char *ibuffer; - FILE *fp; - int pixelSize = mode==GL_RGBA?4:3; - - ibuffer = (unsigned char *) malloc(win_width*win_height*RGB3); - - if ( (fp = fopen(filename, "wb")) == NULL ) { - free(ibuffer); - printf("Warning: cannot open %s\n", filename); - return false; - } - - fprintf(fp, "P6\n# CREATOR: glReadPixel()\n%d %d\n%d\n", - win_width, win_height, UCHAR_MAX); - q = 0; - for (i = 0; i < win_height; i++) - for (j = 0; j < win_width; j++) - for (k = 0; k < RGB3; k++) - ibuffer[q++] = (unsigned char) - *(buffer + (pixelSize*((win_height-1-i)*win_width+j)+k)); - int written = fwrite(ibuffer, sizeof(unsigned char), RGB3*win_width*win_height, fp); - fclose(fp); - free(ibuffer); - - if ( written != RGB3*win_width*win_height ) - { - printf("Warning: failed to write %s. File truncated.\n", filename); - return false; - } - - printf("wrote file '%s' (%d x %d pixels, %d bytes)\n", - filename, win_width, win_height, RGB3*win_width*win_height); - return true; -} - - // dump the screen buffer to a png file, returns true on success bool sg_glDumpWindow(const char *filename, int win_width, int win_height) { osg::ref_ptr img(new osg::Image); diff -Nru simgear-2.10.0/simgear/screen/screen-dump.hxx simgear-3.0.0/simgear/screen/screen-dump.hxx --- simgear-2.10.0/simgear/screen/screen-dump.hxx 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/screen/screen-dump.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -24,10 +24,6 @@ #ifndef SG_SCREEN_DUMP_HXX #define SG_SCREEN_DUMP_HXX -#include - -#include - /** * Dump the screen buffer to a PNG file. * @param filename name of file @@ -37,15 +33,4 @@ bool sg_glDumpWindow( const char *filename, int win_width, int win_height ); -/** - * Given a GLubyte *buffer, write it out to a ppm file. - * @param filename name of file - * @param buffer pointer to opengl buffer - * @param win_width width of buffer - * @param win_height height of buffer - * @param mode one of GL_RGBA, GL_RGB, etc. - */ -bool sg_glWritePPMFile( const char *filename, GLubyte *buffer, int win_width, - int win_height, int mode); - #endif // of SG_SCREEN_DUMP_HXX diff -Nru simgear-2.10.0/simgear/simgear_config_cmake.h.in simgear-3.0.0/simgear/simgear_config_cmake.h.in --- simgear-2.10.0/simgear/simgear_config_cmake.h.in 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/simgear_config_cmake.h.in 2014-02-15 00:04:11.000000000 +0000 @@ -14,9 +14,6 @@ #cmakedefine HAVE_WINDOWS_H #cmakedefine HAVE_MKDTEMP -#cmakedefine HAVE_SVN_CLIENT_H -#cmakedefine HAVE_LIBSVN_CLIENT_1 - #cmakedefine GCC_ATOMIC_BUILTINS_FOUND #cmakedefine SYSTEM_EXPAT diff -Nru simgear-2.10.0/simgear/simgear_config.h-msvc90 simgear-3.0.0/simgear/simgear_config.h-msvc90 --- simgear-2.10.0/simgear/simgear_config.h-msvc90 2011-08-08 13:59:19.000000000 +0000 +++ simgear-3.0.0/simgear/simgear_config.h-msvc90 1970-01-01 00:00:00.000000000 +0000 @@ -1,163 +0,0 @@ -/* simgear_config.h. Generated for MSCV++ 9.0 */ - -/* Define if the X Window System is missing or not being used. */ -#define X_DISPLAY_MISSING 1 - -/* Define to empty if the keyword does not work. */ -/* #undef const */ - -/* Define if you don't have vprintf but do have _doprnt. */ -/* #undef HAVE_DOPRNT */ - -/* Define if you have the vprintf function. */ -#define HAVE_VPRINTF 1 - -/* Define to package name */ -#define PACKAGE "FlightGear" - -/* Define as the return type of signal handlers (int or void). */ -#define RETSIGTYPE void - -/* Define to `unsigned' if doesn't define. */ -/* #undef size_t */ - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if you can safely include both and . */ -/* #undef TIME_WITH_SYS_TIME */ - -/* Define if your declares struct tm. */ -/* #define TM_IN_SYS_TIME 1 */ - -/* Define to version number */ -#define VERSION "2.3.0" - -/* Define if compiling on a Winbloze (95, NT, etc.) platform */ -#define WIN32 1 - -/* Define if you have the GetLocalTime function. */ -#define HAVE_GETLOCALTIME 1 - -/* Define if you have the ftime function. */ -/* #define HAVE_FTIME 1 */ - -/* Define if you have the getitimer function. */ -/* #define HAVE_GETITIMER 1 */ - -/* Define if you have the getrusage function. */ -/* #define HAVE_GETRUSAGE 1 */ - -/* Define if you have the gettimeofday function. */ -/* #define HAVE_GETTIMEOFDAY 1 */ - -/* Define if you have the mktime function. */ -#define HAVE_MKTIME 1 - -/* Define if you have the rand function. */ -#define HAVE_RAND 1 - -/* Define if you have the random function. */ -#define HAVE_RANDOM 1 - -/* Define if you have the rint function. */ -/* #define HAVE_RINT 1 */ - -/* Define if you have the setitimer function. */ -/* #define HAVE_SETITIMER 1 */ - -/* Define if you have the signal function. */ -#define HAVE_SIGNAL 1 - -/* Define if you have the strstr function. */ -#define HAVE_STRSTR 1 - -/* Define if you have the header file. */ -#define HAVE_FCNTL_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_GETOPT_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_MALLOC_H 1 - -/* Define if you have the header file. */ -#define HAVE_STDLIB_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_SYS_TIME_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_SYS_TIMEB_H 1 - -/* Define if you have the header file. */ -/* #define HAVE_UNISTD_H 1 */ - -/* Define if you have the header file. */ -/* #define HAVE_VALUES_H 1 */ - -/* Define if you have the header file. */ -#define HAVE_WINBASE_H 1 - -/* Define if you have the header file. */ -#define HAVE_WINDOWS_H 1 - -/* Define if you have the GL library (-lGL). */ -#define HAVE_LIBGL 1 - -/* Define if you have the GLU library (-lGLU). */ -#define HAVE_LIBGLU 1 - -/* Define if you have the GLcore library (-lGLcore). */ -/* #undef HAVE_LIBGLCORE */ - -/* Define if you have the ICE library (-lICE). */ -/* #define HAVE_LIBICE 1 */ - -/* Define if you have the MesaGL library (-lMesaGL). */ -/* #undef HAVE_LIBMESAGL */ - -/* Define if you have the MesaGLU library (-lMesaGLU). */ -/* #undef HAVE_LIBMESAGLU */ - -/* Define if you have the SM library (-lSM). */ -/* #define HAVE_LIBSM 1 */ - -/* Define if you have the X11 library (-lX11). */ -/* #define HAVE_LIBX11 1 */ - -/* Define if you have the Xext library (-lXext). */ -/* #define HAVE_LIBXEXT 1 */ - -/* Define if you have the Xi library (-lXi). */ -/* #define HAVE_LIBXI 1 */ - -/* Define if you have the Xmu library (-lXmu). */ -/* #define HAVE_LIBXMU 1 */ - -/* Define if you have the Xt library (-lXt). */ -/* #define HAVE_LIBXT 1 */ - -/* Define if you have the glut library (-lglut). */ -#define HAVE_LIBGLUT 1 - -/* Define if you have the m library (-lm). */ -#define HAVE_LIBM 1 - -/* Define if you have the socket library (-lsocket). */ -/* #undef HAVE_LIBSOCKET */ - -/* Define if you have the header file. */ -#define HAVE_MEMORY_H 1 - -#define HAVE_MEMCPY 1 -#define HAVE_DAYLIGHT 1 - -#define GLUT_H - -#define NOMINMAX 1 - -#ifndef _M_X64 -#define HAVE_SVN_CLIENT_H 1 -#define HAVE_LIBSVN_CLIENT_1 1 -#endif // _M_AMD64 diff -Nru simgear-2.10.0/simgear/sound/CMakeLists.txt simgear-3.0.0/simgear/sound/CMakeLists.txt --- simgear-2.10.0/simgear/sound/CMakeLists.txt 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/sound/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -24,14 +24,12 @@ if(ENABLE_TESTS AND ENABLE_SOUND) if (SIMGEAR_SHARED) - set(SOUND_TEST_LIBS SimGearScene) + set( SOUND_TEST_LIBS + ${TEST_LIBS}) else() set(SOUND_TEST_LIBS - SimGearScene SimGearCore - ${CMAKE_THREAD_LIBS_INIT} - ${RT_LIBRARY} - ${OPENAL_LIBRARY} - ${ZLIB_LIBRARY}) + ${TEST_LIBS} + ${OPENAL_LIBRARY}) endif() function(create_test TEST_NAME) diff -Nru simgear-2.10.0/simgear/sound/openal_test2.cxx simgear-3.0.0/simgear/sound/openal_test2.cxx --- simgear-2.10.0/simgear/sound/openal_test2.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/sound/openal_test2.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -8,6 +8,7 @@ #include #include +#include #include "soundmgr_openal.hxx" #include "sample_group.hxx" @@ -90,7 +91,7 @@ sgr->stop("sound1"); sgr->stop("sound2"); sgr->stop("sound3"); - sleep(0.5); + SGTimeStamp::sleepForMSec(500); smgr->update(0.5); sgr->stop("sound4"); sgr->stop("sound5"); diff -Nru simgear-2.10.0/simgear/sound/sample_group.cxx simgear-3.0.0/simgear/sound/sample_group.cxx --- simgear-2.10.0/simgear/sound/sample_group.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/sound/sample_group.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -35,6 +35,10 @@ using std::string; +#ifdef HAVE_STD_ISNAN +using std::isnan; +#endif + bool isNaN(float *v) { return (isnan(v[0]) || isnan(v[1]) || isnan(v[2])); } diff -Nru simgear-2.10.0/simgear/sound/sample_queue.hxx simgear-3.0.0/simgear/sound/sample_queue.hxx --- simgear-2.10.0/simgear/sound/sample_queue.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/sound/sample_queue.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -91,7 +91,6 @@ private: std::string _refname; // sample name std::vector _buffers; - unsigned int _buffer; bool _playing; diff -Nru simgear-2.10.0/simgear/structure/CMakeLists.txt simgear-3.0.0/simgear/structure/CMakeLists.txt --- simgear-2.10.0/simgear/structure/CMakeLists.txt 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/structure/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -22,7 +22,9 @@ event_mgr.hxx exception.hxx intern.hxx + map.hxx subsystem_mgr.hxx + StateMachine.hxx ) set(SOURCES @@ -36,7 +38,20 @@ commands.cxx event_mgr.cxx exception.cxx - subsystem_mgr.cxx + subsystem_mgr.cxx + StateMachine.cxx ) simgear_component(structure structure "${SOURCES}" "${HEADERS}") + +if(ENABLE_TESTS) + +add_executable(test_state_machine state_machine_test.cxx) +target_link_libraries(test_state_machine ${TEST_LIBS}) +add_test(state_machine ${EXECUTABLE_OUTPUT_PATH}/test_state_machine) + +add_executable(test_expressions expression_test.cxx) +target_link_libraries(test_expressions ${TEST_LIBS}) +add_test(expressions ${EXECUTABLE_OUTPUT_PATH}/test_expressions) + +endif(ENABLE_TESTS) diff -Nru simgear-2.10.0/simgear/structure/commands.cxx simgear-3.0.0/simgear/structure/commands.cxx --- simgear-2.10.0/simgear/structure/commands.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/structure/commands.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -9,6 +9,8 @@ #endif #include +#include + #include #include "commands.hxx" @@ -23,41 +25,36 @@ // Implementation of SGCommandMgr class. //////////////////////////////////////////////////////////////////////// +static SGCommandMgr* static_instance = NULL; SGCommandMgr::SGCommandMgr () { - // no-op + assert(static_instance == NULL); + static_instance = this; } SGCommandMgr::~SGCommandMgr () { - // no-op + assert(static_instance == this); + static_instance = NULL; } -SGMutex SGCommandMgr::_instanceMutex; - SGCommandMgr* SGCommandMgr::instance() { - static std::auto_ptr mgr; - if (mgr.get()) - return mgr.get(); - - SGGuard lock(_instanceMutex); - if (mgr.get()) - return mgr.get(); - - mgr = std::auto_ptr(new SGCommandMgr); - return mgr.get(); + return static_instance ? static_instance : new SGCommandMgr; } void -SGCommandMgr::addCommand (const std::string &name, command_t command) +SGCommandMgr::addCommandObject (const std::string &name, Command* command) { + if (_commands.find(name) != _commands.end()) + throw sg_exception("duplicate command name:" + name); + _commands[name] = command; } -SGCommandMgr::command_t +SGCommandMgr::Command* SGCommandMgr::getCommand (const std::string &name) const { const command_map::const_iterator it = _commands.find(name); @@ -80,18 +77,58 @@ bool SGCommandMgr::execute (const std::string &name, const SGPropertyNode * arg) const { - command_t command = getCommand(name); + Command* command = getCommand(name); if (command == 0) + { + SG_LOG(SG_GENERAL, SG_WARN, "command not found: '" << name << "'"); return false; + } - - try { + try + { return (*command)(arg); - } catch (sg_exception& e) { - SG_LOG(SG_GENERAL, SG_ALERT, "command '" << name << "' failed with exception\n" - << "\tmessage:" << e.getMessage() << " (from " << e.getOrigin() << ")"); - return false; } + catch(sg_exception& e) + { + SG_LOG + ( + SG_GENERAL, + SG_ALERT, + "command '" << name << "' failed with exception\n" + "\tmessage:" << e.getMessage() << " (from " << e.getOrigin() << ")" + ); + } + catch(std::exception& ex) + { + SG_LOG + ( + SG_GENERAL, + SG_ALERT, + "command '" << name << "' failed with exception: " << ex.what() + ); + } + catch(...) + { + SG_LOG + ( + SG_GENERAL, + SG_ALERT, + "command '" << name << "' failed with unknown exception." + ); + } + + return false; +} + +bool SGCommandMgr::removeCommand(const std::string& name) +{ + command_map::iterator it = _commands.find(name); + if (it == _commands.end()) + return false; + + delete it->second; + _commands.erase(it); + return true; } // end of commands.cxx diff -Nru simgear-2.10.0/simgear/structure/commands.hxx simgear-3.0.0/simgear/structure/commands.hxx --- simgear-2.10.0/simgear/structure/commands.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/structure/commands.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -15,12 +15,12 @@ #include #include -#include -#include #include -#include +// forward decls +class SGPropertyNode; + /** * Manage commands. * @@ -34,21 +34,68 @@ class SGCommandMgr { public: + /** + * Command functor object + */ + class Command + { + public: + virtual ~Command() { } + virtual bool operator()(const SGPropertyNode * arg) = 0; + }; - /** - * Type for a command function. - */ - typedef bool (*command_t) (const SGPropertyNode * arg); + + typedef bool (*command_t) (const SGPropertyNode * arg); +private: + class FunctionCommand : public Command + { + public: + FunctionCommand( command_t fun ) + : f_(fun) {} + + virtual bool operator()(const SGPropertyNode * arg) { return (*f_)(arg); } + private: + command_t f_; + }; + + template< class ObjPtr, typename MemFn > + class MethodCommand : public Command + { + public: + MethodCommand( const ObjPtr& pObj, MemFn pMemFn ) : + pObj_(pObj), pMemFn_(pMemFn) {} + + virtual bool operator()(const SGPropertyNode * arg) + { + return ((*pObj_).*pMemFn_)(arg); + } + private: + ObjPtr pObj_; + MemFn pMemFn_; + }; + + /** + * Helper template functions. + */ + + template< class ObjPtr, typename MemFn > + Command* make_functor( const ObjPtr& pObj, MemFn pMemFn ) + { + return new MethodCommand(pObj, pMemFn ); + } + +public: + /** + * Default constructor (sets instance to created item) + */ + SGCommandMgr (); /** - * Destructor. + * Destructor. (sets instance to NULL) */ virtual ~SGCommandMgr (); - /** - * Implement the classical singleton. - */ static SGCommandMgr* instance(); /** @@ -60,9 +107,17 @@ * a bool result. The argument is always a const pointer to * an SGPropertyNode (which may contain multiple values). */ - virtual void addCommand (const std::string &name, command_t command); - - + void addCommand(const std::string& name, command_t f) + { addCommandObject(name, new FunctionCommand(f)); } + + void addCommandObject (const std::string &name, Command* command); + + template + void addCommand(const std::string& name, const OBJ& o, METHOD m) + { + addCommandObject(name, make_functor(o,m)); + } + /** * Look up an existing command. * @@ -70,7 +125,7 @@ * @return A pointer to the command, or 0 if there is no registered * command with the name specified. */ - virtual command_t getCommand (const std::string &name) const; + virtual Command* getCommand (const std::string &name) const; /** @@ -94,20 +149,19 @@ */ virtual bool execute (const std::string &name, const SGPropertyNode * arg) const; -protected: /** - * Default constructor. + * Remove a command registration */ - SGCommandMgr (); + bool removeCommand(const std::string& name); +protected: + private: - typedef std::map command_map; + typedef std::map command_map; command_map _commands; - static SGMutex _instanceMutex; - }; #endif // __COMMANDS_HXX diff -Nru simgear-2.10.0/simgear/structure/event_mgr.cxx simgear-3.0.0/simgear/structure/event_mgr.cxx --- simgear-2.10.0/simgear/structure/event_mgr.cxx 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/structure/event_mgr.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -12,7 +12,8 @@ { // Clamp the delay value to 1 usec, so that user code can use // "zero" as a synonym for "next frame". - if(delay <= 0) delay = 0.000001; + if(delay <= 0) delay = 1e-6; + if(interval <= 0) interval = 1e-6; // No timer endless loops please... SGTimer* t = new SGTimer; t->interval = interval; @@ -37,6 +38,28 @@ (*callback)(); } +SGEventMgr::SGEventMgr() +{ + +} + +SGEventMgr::~SGEventMgr() +{ + +} + +void SGEventMgr::unbind() +{ + _freezeProp.clear(); + _rtProp.clear(); +} + +void SGEventMgr::shutdown() +{ + _simQueue.clear(); + _rtQueue.clear(); +} + void SGEventMgr::update(double delta_time_sec) { _simQueue.update(delta_time_sec); @@ -80,7 +103,7 @@ _table = new HeapEntry[_tableSize]; for(int i=0; i<_tableSize; i++) { - _table[i].pri = 0; + _table[i].pri = 0; _table[i].timer = 0; } } @@ -88,14 +111,24 @@ SGTimerQueue::~SGTimerQueue() { + clear(); + delete[] _table; +} + +void SGTimerQueue::clear() +{ + // delete entries for(int i=0; i<_numEntries; i++) { delete _table[i].timer; - _table[i].timer = 0; } + _numEntries = 0; - delete[] _table; - _table = 0; - _tableSize = 0; + + // clear entire table to empty + for(int i=0; i<_tableSize; i++) { + _table[i].pri = 0; + _table[i].timer = 0; + } } void SGTimerQueue::update(double deltaSecs) diff -Nru simgear-2.10.0/simgear/structure/event_mgr.hxx simgear-3.0.0/simgear/structure/event_mgr.hxx --- simgear-2.10.0/simgear/structure/event_mgr.hxx 2011-06-29 14:58:56.000000000 +0000 +++ simgear-3.0.0/simgear/structure/event_mgr.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -25,6 +25,7 @@ SGTimerQueue(int preSize=1); ~SGTimerQueue(); + void clear(); void update(double deltaSecs); double now() { return _now; } @@ -68,12 +69,14 @@ class SGEventMgr : public SGSubsystem { public: - SGEventMgr() { _rtProp = 0; } - ~SGEventMgr() { _rtProp = 0; } + SGEventMgr(); + ~SGEventMgr(); virtual void init() {} virtual void update(double delta_time_sec); - + virtual void unbind(); + virtual void shutdown(); + void setRealtimeProperty(SGPropertyNode* node) { _rtProp = node; } /** diff -Nru simgear-2.10.0/simgear/structure/expression_test.cxx simgear-3.0.0/simgear/structure/expression_test.cxx --- simgear-2.10.0/simgear/structure/expression_test.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/structure/expression_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,110 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef NDEBUG +// Always enable DEBUG mode in test application, otherwise "assert" test +// statements have no effect and don't actually test anything (catch 17 ;-) ). +#undef NDEBUG +#endif + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace simgear; + +SGPropertyNode_ptr propertyTree; + +void initPropTree() +{ + const char* xml = "" + "" + "" + "one" + "2" + "99" + "" + "" + "false" + "" + ""; + + propertyTree = new SGPropertyNode; + readProperties(xml, strlen(xml), propertyTree.ptr()); +} + +void testBasic() +{ + +} + +void testParse() +{ + initPropTree(); +#if 0 + const char* xml = "" + "" + "" + "" + "" + "/group-a/bar" + "42" + "" + "" + "/group-a/zot" + "50" + "" + "" + "" + ""; +#endif + const char* xml2 = "" + "" + "" + "" + "/group-a/bar" + "/group-a/zot" + "/group-b/thing-1" + "" + "" + ""; + + SGPropertyNode* desc = new SGPropertyNode; + readProperties(xml2, strlen(xml2), desc); + + SGSharedPtr expr = SGReadDoubleExpression(propertyTree, desc->getChild(0)); + + std::set deps; + expr->collectDependentProperties(deps); + + COMPARE(deps.size(), 3); + SGPropertyNode* barProp = propertyTree->getNode("group-a/bar"); + VERIFY(deps.find(barProp) != deps.end()); + + VERIFY(deps.find(propertyTree->getNode("group-a/zot")) != deps.end()); + VERIFY(deps.find(propertyTree->getNode("group-b/thing-1")) != deps.end()); +} + +int main(int argc, char* argv[]) +{ + sglog().setLogLevels( SG_ALL, SG_INFO ); + + testBasic(); + testParse(); + + cout << __FILE__ << ": All tests passed" << endl; + return EXIT_SUCCESS; +} + diff -Nru simgear-2.10.0/simgear/structure/map.hxx simgear-3.0.0/simgear/structure/map.hxx --- simgear-2.10.0/simgear/structure/map.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/structure/map.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,69 @@ +///@file Extended std::map with methods for easier usage. +// +// Copyright (C) 2013 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_MAP_HXX_ +#define SG_MAP_HXX_ + +#include +#include + +namespace simgear +{ + + template + class Map: + public std::map + { + public: + Map() {} + + /** + * Initilize a new mape with the given key/value pair. + */ + Map(const Key& key, const Value& value) + { + (*this)[key] = value; + } + + /** + * Change/add new value. + */ + Map& operator()(const Key& key, const Value& value) + { + (*this)[key] = value; + return *this; + } + + /** + * Retrive a value (or get a default value if it does not exist). + */ + Value get(const Key& key, const Value& def = Value()) const + { + typename Map::const_iterator it = this->find(key); + if( it != this->end() ) + return it->second; + + return def; + } + }; + + typedef Map StringMap; + +} // namespace simgear + +#endif /* SG_MAP_HXX_ */ diff -Nru simgear-2.10.0/simgear/structure/SGBinding.cxx simgear-3.0.0/simgear/structure/SGBinding.cxx --- simgear-2.10.0/simgear/structure/SGBinding.cxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/structure/SGBinding.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -11,9 +11,11 @@ # include #endif +#include #include #include "SGBinding.hxx" +#include #include SGBinding::SGBinding() @@ -23,6 +25,14 @@ { } +SGBinding::SGBinding(const std::string& commandName) + : _command(0), + _arg(0), + _setting(0) +{ + _command_name = commandName; +} + SGBinding::SGBinding(const SGPropertyNode* node, SGPropertyNode* root) : _command(0), _arg(0), @@ -38,6 +48,14 @@ } void +SGBinding::clear() +{ + _command = NULL; + _arg.clear(); + _setting.clear(); +} + +void SGBinding::read(const SGPropertyNode* node, SGPropertyNode* root) { const SGPropertyNode * conditionNode = node->getChild("condition"); @@ -55,25 +73,42 @@ } void -SGBinding::fire () const +SGBinding::fire() const { if (test()) { - if (_command == 0) - _command = SGCommandMgr::instance()->getCommand(_command_name); - if (_command == 0) { - SG_LOG(SG_INPUT, SG_WARN, "No command attached to binding"); - } else - { - try { - if (!(*_command)(_arg)) { - SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command " - << _command_name); - } - } catch (sg_exception& e) { - SG_LOG(SG_GENERAL, SG_ALERT, "command '" << _command_name << "' failed with exception\n" - << "\tmessage:" << e.getMessage() << " (from " << e.getOrigin() << ")"); - } + innerFire(); + } +} + +void +SGBinding::innerFire () const +{ + if (_command == 0) + _command = SGCommandMgr::instance()->getCommand(_command_name); + if (_command == 0) { + SG_LOG(SG_INPUT, SG_WARN, "No command attached to binding:" << _command_name); + } else { + try { + if (!(*_command)(_arg)) { + SG_LOG(SG_INPUT, SG_ALERT, "Failed to execute command " + << _command_name); + } + } catch (sg_exception& e) { + SG_LOG(SG_GENERAL, SG_ALERT, "command '" << _command_name << "' failed with exception\n" + << "\tmessage:" << e.getMessage() << " (from " << e.getOrigin() << ")"); + } + } +} + +void +SGBinding::fire (SGPropertyNode* params) const +{ + if (test()) { + if (params != NULL) { + copyProperties(params, _arg); } + + innerFire(); } } @@ -82,7 +117,7 @@ { if (test()) { _arg->setDoubleValue("offset", offset/max); - fire(); + innerFire(); } } @@ -95,6 +130,38 @@ if (_setting == 0) // save the setting node for efficiency _setting = _arg->getChild("setting", 0, true); _setting->setDoubleValue(setting); - fire(); + innerFire(); } } + +void fireBindingList(const SGBindingList& aBindings, SGPropertyNode* params) +{ + BOOST_FOREACH(SGBinding_ptr b, aBindings) { + b->fire(params); + } +} + +void fireBindingListWithOffset(const SGBindingList& aBindings, double offset, double max) +{ + BOOST_FOREACH(SGBinding_ptr b, aBindings) { + b->fire(offset, max); + } +} + +SGBindingList readBindingList(const simgear::PropertyList& aNodes, SGPropertyNode* aRoot) +{ + SGBindingList result; + BOOST_FOREACH(SGPropertyNode* node, aNodes) { + result.push_back(new SGBinding(node, aRoot)); + } + + return result; +} + +void clearBindingList(const SGBindingList& aBindings) +{ + BOOST_FOREACH(SGBinding_ptr b, aBindings) { + b->clear(); + } +} + diff -Nru simgear-2.10.0/simgear/structure/SGBinding.hxx simgear-3.0.0/simgear/structure/SGBinding.hxx --- simgear-2.10.0/simgear/structure/SGBinding.hxx 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/simgear/structure/SGBinding.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -38,6 +38,12 @@ */ SGBinding (); + /** + * Convenience constructor. + * + * @param node The binding will be built from this node. + */ + SGBinding(const std::string& commandName); /** * Convenience constructor. @@ -52,6 +58,14 @@ */ virtual ~SGBinding (); + + /** + * clear internal state of the binding back to empty. This is useful + * if you don't want the 'remove on delete' behaviour of the + * destructor. + */ + void clear(); + /** * Get the command name. @@ -67,7 +81,7 @@ * @return The command associated with this binding, or 0 if none * is present. */ - SGCommandMgr::command_t getCommand () const { return _command; } + SGCommandMgr::Command* getCommand () const { return _command; } /** @@ -108,18 +122,49 @@ */ void fire (double setting) const; - + /** + * Fire a binding with a number of additional parameters + * + * The children of params will be merged with the fixed arguments. + */ + void fire (SGPropertyNode* params) const; + private: + void innerFire() const; // just to be safe. SGBinding (const SGBinding &binding); std::string _command_name; - mutable SGCommandMgr::command_t _command; + mutable SGCommandMgr::Command* _command; mutable SGPropertyNode_ptr _arg; mutable SGPropertyNode_ptr _setting; }; -typedef std::vector > SGBindingList; +typedef SGSharedPtr SGBinding_ptr; + +typedef std::vector SGBindingList; typedef std::map SGBindingMap; +/** + * fire every binding in a list, in sequence + + */ +void fireBindingList(const SGBindingList& aBindings, SGPropertyNode* params = NULL); + +/** + * fire every binding in a list with a setting value + + */ +void fireBindingListWithOffset(const SGBindingList& aBindings, double offset, double max); + +/** + * read multiple bindings from property-list format + */ +SGBindingList readBindingList(const simgear::PropertyList& aNodes, SGPropertyNode* aRoot); + +/** + * call clear() on every binding in a list + */ +void clearBindingList(const SGBindingList& aBindings); + #endif diff -Nru simgear-2.10.0/simgear/structure/SGExpression.cxx simgear-3.0.0/simgear/structure/SGExpression.cxx --- simgear-2.10.0/simgear/structure/SGExpression.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/structure/SGExpression.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -865,7 +865,7 @@ ExpParserRegistrar andRegistrar("and", logicopParser); ExpParserRegistrar orRegistrar("or", logicopParser); -int BindingLayout::addBinding(const string& name, Type type) +size_t BindingLayout::addBinding(const string& name, Type type) { //XXX error checkint vector::iterator itr @@ -873,7 +873,7 @@ boost::bind(&VariableBinding::name, _1) == name); if (itr != bindings.end()) return itr->location; - int result = bindings.size(); + size_t result = bindings.size(); bindings.push_back(VariableBinding(name, type, bindings.size())); return result; } diff -Nru simgear-2.10.0/simgear/structure/SGExpression.hxx simgear-3.0.0/simgear/structure/SGExpression.hxx --- simgear-2.10.0/simgear/structure/SGExpression.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/structure/SGExpression.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -25,6 +25,8 @@ #include #include #include +#include +#include #include #include @@ -136,6 +138,8 @@ { return simgear::expression::TypeTraits::typeTag; } + virtual void collectDependentProperties(std::set& props) const + { } }; /// Constant value expression @@ -184,7 +188,9 @@ _expression = _expression->simplify(); return SGExpression::simplify(); } - + + virtual void collectDependentProperties(std::set& props) const + { _expression->collectDependentProperties(props); } protected: SGUnaryExpression(SGExpression* expression = 0) { setOperand(expression); } @@ -218,6 +224,12 @@ return SGExpression::simplify(); } + virtual void collectDependentProperties(std::set& props) const + { + _expressions[0]->collectDependentProperties(props); + _expressions[1]->collectDependentProperties(props); + } + protected: SGBinaryExpression(SGExpression* expr0, SGExpression* expr1) { setOperand(0, expr0); setOperand(1, expr1); } @@ -266,6 +278,11 @@ return SGExpression::simplify(); } + virtual void collectDependentProperties(std::set& props) const + { + for (size_t i = 0; i < _expressions.size(); ++i) + _expressions[i]->collectDependentProperties(props); + } protected: SGNaryExpression() { } @@ -288,6 +305,9 @@ { _prop = prop; } virtual void eval(T& value, const simgear::expression::Binding*) const { doEval(value); } + + virtual void collectDependentProperties(std::set& props) const + { props.insert(_prop.get()); } private: void doEval(float& value) const { if (_prop) value = _prop->getFloatValue(); } @@ -713,6 +733,12 @@ return getOperand()->simplify(); return SGUnaryExpression::simplify(); } + + virtual void collectDependentProperties(std::set& props) const + { + SGUnaryExpression::collectDependentProperties(props); + _enable->collectDependentProperties(props); + } using SGUnaryExpression::getOperand; private: @@ -875,6 +901,11 @@ typedef SGExpression SGExpressiond; typedef SGExpression SGExpressionb; +typedef SGSharedPtr SGExpressioni_ref; +typedef SGSharedPtr SGExpressionf_ref; +typedef SGSharedPtr SGExpressiond_ref; +typedef SGSharedPtr SGExpressionb_ref; + /** * Global function to make an expression out of properties. @@ -919,7 +950,7 @@ { struct ParseError : public sg_exception { - ParseError(const string& message = std::string()) + ParseError(const std::string& message = std::string()) : sg_exception(message) {} }; @@ -983,8 +1014,8 @@ class BindingLayout { public: - int addBinding(const std::string& name, expression::Type type); - bool findBinding(const string& name, VariableBinding& result) const; + size_t addBinding(const std::string& name, expression::Type type); + bool findBinding(const std::string& name, VariableBinding& result) const; std::vector bindings; }; @@ -1001,7 +1032,7 @@ ParserMap& map = getParserMap(); ParserMap::iterator itr = map.find(exp->getName()); if (itr == map.end()) - throw ParseError(string("unknown expression ") + exp->getName()); + throw ParseError(std::string("unknown expression ") + exp->getName()); exp_parser parser = itr->second; return (*parser)(exp, this); } diff -Nru simgear-2.10.0/simgear/structure/SGSharedPtr.hxx simgear-3.0.0/simgear/structure/SGSharedPtr.hxx --- simgear-2.10.0/simgear/structure/SGSharedPtr.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/structure/SGSharedPtr.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -123,4 +123,51 @@ { return p.ptr(); } + +/** + * static_cast for SGSharedPtr + */ +template +SGSharedPtr static_pointer_cast(SGSharedPtr const & r) +{ + return SGSharedPtr( static_cast(r.get()) ); +} + +/** + * Compare two SGSharedPtr objects for equality. + * + * @note Only pointer values are compared, not the actual objects they are + * pointing at. + */ +template +bool operator==(const SGSharedPtr& lhs, const SGSharedPtr& rhs) +{ + return lhs.get() == rhs.get(); +} + +/** + * Compare two SGSharedPtr objects for equality. + * + * @note Only pointer values are compared, not the actual objects they are + * pointing at. + */ +template +bool operator!=(const SGSharedPtr& lhs, const SGSharedPtr& rhs) +{ + return lhs.get() != rhs.get(); +} + +/** + * Compare two SGSharedPtr objects for weak ordering. + * + * @note Only pointer values are compared, not the actual objects they are + * pointing at. + * @note This allows using SGSharedPtr as key in associative containers like for + * example std::map and std::set. + */ +template +bool operator<(const SGSharedPtr& lhs, const SGSharedPtr& rhs) +{ + return lhs.get() < rhs.get(); +} #endif diff -Nru simgear-2.10.0/simgear/structure/SGWeakReferenced.hxx simgear-3.0.0/simgear/structure/SGWeakReferenced.hxx --- simgear-2.10.0/simgear/structure/SGWeakReferenced.hxx 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/structure/SGWeakReferenced.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -21,6 +21,13 @@ #include "SGReferenced.hxx" #include "SGSharedPtr.hxx" +#ifdef _MSC_VER +# pragma warning(push) + // C4355: 'this' : used in base member initializer list + // Tell MSVC we know what we do and really want to do it this way. +# pragma warning(disable: 4355) +#endif + template class SGWeakPtr; @@ -100,4 +107,8 @@ friend class SGWeakPtr; }; +#ifdef _MSC_VER +# pragma warning(pop) +#endif + #endif diff -Nru simgear-2.10.0/simgear/structure/StateMachine.cxx simgear-3.0.0/simgear/structure/StateMachine.cxx --- simgear-2.10.0/simgear/structure/StateMachine.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/structure/StateMachine.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,493 @@ +/* -*-c++-*- + * + * Copyright (C) 2013 James Turner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "StateMachine.hxx" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace simgear +{ + +typedef std::vector StatePtrVec; + +static void readBindingList(SGPropertyNode* desc, const std::string& name, + SGPropertyNode* root, SGBindingList& result) +{ + BOOST_FOREACH(SGPropertyNode* b, desc->getChildren(name)) { + SGBinding* bind = new SGBinding; + bind->read(b, root); + result.push_back(bind); + } +} + +/////////////////////////////////////////////////////////////////////////// + +class StateMachine::State::StatePrivate +{ +public: + std::string _name; + SGBindingList _updateBindings, + _entryBindings, + _exitBindings; +}; + +/////////////////////////////////////////////////////////////////////////// + +class StateMachine::Transition::TransitionPrivate +{ +public: + std::string _name; + SGBindingList _bindings; + std::set _sourceStates; ///< weak refs to source states + State* _target; + bool _excludeTarget; + SGSharedPtr _condition; +}; + +/////////////////////////////////////////////////////////////////////////// + +class StateMachine::StateMachinePrivate : public SGPropertyChangeListener +{ +public: + StateMachinePrivate(StateMachine* p) : _p(p) { } + + void computeEligibleTransitions() + { + _eligible.clear(); + BOOST_FOREACH(Transition_ptr t, _transitions) { + if (t->applicableForState(_currentState)) { + _eligible.push_back(t.ptr()); + } + } + } + + StateMachine* _p; + bool _initialised; + State_ptr _currentState; + StatePtrVec _states; + std::vector _transitions; + std::vector _eligible; + SGTimeStamp _timeInState; + + bool _listenerLockout; ///< block our listener when self-updating props + virtual void valueChanged(SGPropertyNode* changed) + { + if (_listenerLockout) { + return; + } + + if (changed == _currentStateIndex) { + State_ptr s = _p->stateByIndex(changed->getIntValue()); + _p->changeToState(s); + } else if (changed == _currentStateName) { + _p->changeToStateName(changed->getStringValue()); + } + } + +// exposed properties + SGPropertyNode_ptr _root; + SGPropertyNode_ptr _currentStateIndex; + SGPropertyNode_ptr _currentStateName; + SGPropertyNode_ptr _timeInStateProp; +}; + +/////////////////////////////////////////////////////////////////////////// + +StateMachine::State::State(const std::string& aName) : + d(new StatePrivate) +{ + d->_name = aName; +} + +StateMachine::State::~State() +{ +} + +std::string StateMachine::State::name() const +{ + return d->_name; +} + +void StateMachine::State::update() +{ + fireBindingList(d->_updateBindings); +} + +void StateMachine::State::fireEntryBindings() +{ + fireBindingList(d->_entryBindings); +} + +void StateMachine::State::fireExitBindings() +{ + fireBindingList(d->_exitBindings); +} + +void StateMachine::State::addUpdateBinding(SGBinding* aBinding) +{ + d->_updateBindings.push_back(aBinding); +} + +void StateMachine::State::addEntryBinding(SGBinding* aBinding) +{ + d->_entryBindings.push_back(aBinding); +} + +void StateMachine::State::addExitBinding(SGBinding* aBinding) +{ + d->_exitBindings.push_back(aBinding); +} + +/////////////////////////////////////////////////////////////////////////// + +StateMachine::Transition::Transition(const std::string& aName, State* aTarget) : + d(new TransitionPrivate) +{ + assert(aTarget); + d->_name = aName; + d->_target = aTarget; + d->_excludeTarget = true; +} + +StateMachine::Transition::~Transition() +{ +} + +StateMachine::State* StateMachine::Transition::target() const +{ + return d->_target; +} + +void StateMachine::Transition::addSourceState(State* aSource) +{ + if (aSource == d->_target) { // should this be disallowed outright? + SG_LOG(SG_GENERAL, SG_WARN, d->_name << ": adding target state as source"); + } + + d->_sourceStates.insert(aSource); +} + +bool StateMachine::Transition::applicableForState(State* aCurrent) const +{ + if (d->_excludeTarget && (aCurrent == d->_target)) { + return false; + } + + if (d->_sourceStates.empty()) { + return true; + } + return d->_sourceStates.count(aCurrent); +} + +bool StateMachine::Transition::evaluate() const +{ + return d->_condition->test(); +} + +void StateMachine::Transition::fireBindings() +{ + fireBindingList(d->_bindings); +} + +std::string StateMachine::Transition::name() const +{ + return d->_name; +} + +void StateMachine::Transition::setTriggerCondition(SGCondition* aCondition) +{ + d->_condition = aCondition; +} + +void StateMachine::Transition::addBinding(SGBinding* aBinding) +{ + d->_bindings.push_back(aBinding); +} + +void StateMachine::Transition::setExcludeTarget(bool aExclude) +{ + d->_excludeTarget = aExclude; +} + +/////////////////////////////////////////////////////////////////////////// + +StateMachine::StateMachine() : + d(new StateMachinePrivate(this)) +{ + d->_root = new SGPropertyNode(); + d->_listenerLockout = false; + d->_initialised = false; +} + +StateMachine::~StateMachine() +{ + +} + +void StateMachine::init() +{ + if (d->_initialised) { + return; + } + + if (d->_states.empty()) { + throw sg_range_exception("StateMachine::init: no states defined"); + } + + d->_currentStateIndex = d->_root->getChild("current-index", 0, true); + d->_currentStateIndex->setIntValue(0); + + d->_currentStateName = d->_root->getChild("current-name", 0, true); + d->_currentStateName->setStringValue(""); + + d->_currentStateIndex->addChangeListener(d.get()); + d->_currentStateName->addChangeListener(d.get()); + + d->_timeInStateProp = d->_root->getChild("elapsed-time-msec", 0, true); + d->_timeInStateProp->setIntValue(0); + + // TODO go to default state if found + innerChangeState(d->_states[0], NULL); + d->_initialised = true; +} + +void StateMachine::shutdown() +{ + d->_currentStateIndex->removeChangeListener(d.get()); + d->_currentStateName->removeChangeListener(d.get()); + +} + +void StateMachine::innerChangeState(State_ptr aState, Transition_ptr aTrans) +{ + if (d->_currentState) { + d->_currentState->fireExitBindings(); + } + +// fire bindings before we change the state, hmmmm + if (aTrans) { + aTrans->fireBindings(); + } + + // update our private state and properties + d->_listenerLockout = true; + d->_currentState = aState; + d->_timeInState.stamp(); + d->_currentStateName->setStringValue(d->_currentState->name()); + d->_currentStateIndex->setIntValue(indexOfState(aState)); + d->_timeInStateProp->setIntValue(0); + d->_listenerLockout = false; + + // fire bindings + d->_currentState->fireEntryBindings(); + d->_currentState->update(); + + d->computeEligibleTransitions(); +} + +void StateMachine::changeToState(State_ptr aState, bool aOnlyIfDifferent) +{ + assert(aState != NULL); + if (std::find(d->_states.begin(), d->_states.end(), aState) == d->_states.end()) { + throw sg_exception("Requested change to state not in machine"); + } + + if (aOnlyIfDifferent && (aState == d->_currentState)) { + return; + } + + innerChangeState(aState, NULL); +} + +void StateMachine::changeToStateName(const std::string& aName, bool aOnlyIfDifferent) +{ + State_ptr st = findStateByName(aName); + if (!st) { + throw sg_range_exception("unknown state:" + aName); + } + + changeToState(st, aOnlyIfDifferent); +} + +StateMachine::State_ptr StateMachine::state() const +{ + return d->_currentState; +} + +SGPropertyNode* StateMachine::root() +{ + return d->_root; +} + +void StateMachine::update(double aDt) +{ + // do this first, for triggers which depend on time in current state + // (spring-loaded transitions) + d->_timeInStateProp->setIntValue(d->_timeInState.elapsedMSec()); + + Transition_ptr trigger; + + BOOST_FOREACH(Transition* trans, d->_eligible) { + if (trans->evaluate()) { + if (trigger != Transition_ptr()) { + SG_LOG(SG_GENERAL, SG_WARN, "ambiguous transitions! " + << trans->name() << " or " << trigger->name()); + } + + trigger = trans; + } + } + + if (trigger != Transition_ptr()) { + SG_LOG(SG_GENERAL, SG_DEBUG, "firing transition:" << trigger->name()); + innerChangeState(trigger->target(), trigger); + } + + d->_currentState->update(); +} + +StateMachine::State_ptr StateMachine::findStateByName(const std::string& aName) const +{ + BOOST_FOREACH(State_ptr sp, d->_states) { + if (sp->name() == aName) { + return sp; + } + } + + SG_LOG(SG_GENERAL, SG_WARN, "unknown state:" << aName); + return State_ptr(); +} + +StateMachine::State_ptr StateMachine::stateByIndex(unsigned int aIndex) const +{ + if (aIndex >= d->_states.size()) { + throw sg_range_exception("invalid state index, out of bounds"); + } + + return d->_states[aIndex]; +} + +int StateMachine::indexOfState(State_ptr aState) const +{ + StatePtrVec::const_iterator it = std::find(d->_states.begin(), d->_states.end(), aState); + if (it == d->_states.end()) { + return -1; + } + + return it - d->_states.begin(); +} + +StateMachine::State_ptr StateMachine::createState(const std::string& aName) +{ + if (findStateByName(aName) != NULL) { + throw sg_range_exception("duplicate state name"); + } + + State_ptr st = new State(aName); + addState(st); + return st; +} + +StateMachine::Transition_ptr +StateMachine::createTransition(const std::string& aName, State_ptr aTarget) +{ + Transition_ptr t = new Transition(aName, aTarget); + addTransition(t); + return t; +} + +void StateMachine::initFromPlist(SGPropertyNode* desc, SGPropertyNode* root) +{ + std::string path = desc->getStringValue("branch"); + if (!path.empty()) { + d->_root = root->getNode(path, 0, true); + assert(d->_root); + } + + BOOST_FOREACH(SGPropertyNode* stateDesc, desc->getChildren("state")) { + std::string nm = stateDesc->getStringValue("name"); + State_ptr st(new State(nm)); + + readBindingList(stateDesc, "enter", root, st->d->_updateBindings); + readBindingList(stateDesc, "exit", root, st->d->_entryBindings); + readBindingList(stateDesc, "update", root, st->d->_exitBindings); + + addState(st); + } // of states iteration + + BOOST_FOREACH(SGPropertyNode* tDesc, desc->getChildren("transition")) { + std::string nm = tDesc->getStringValue("name"); + State_ptr target = findStateByName(tDesc->getStringValue("target")); + + SGCondition* cond = sgReadCondition(root, tDesc->getChild("condition")); + + Transition_ptr t(new Transition(nm, target)); + t->setTriggerCondition(cond); + + t->setExcludeTarget(tDesc->getBoolValue("exclude-target", true)); + BOOST_FOREACH(SGPropertyNode* src, desc->getChildren("source")) { + State_ptr srcState = findStateByName(src->getStringValue()); + t->addSourceState(srcState); + } + + readBindingList(tDesc, "binding", root, t->d->_bindings); + + addTransition(t); + } // of states iteration + + init(); +} + +StateMachine* StateMachine::createFromPlist(SGPropertyNode* desc, SGPropertyNode* root) +{ + StateMachine* sm = new StateMachine; + sm->initFromPlist(desc, root); + return sm; +} + +void StateMachine::addState(State_ptr aState) +{ + bool wasEmpty = d->_states.empty(); + d->_states.push_back(aState); + if (wasEmpty) { + d->_currentState = aState; + } +} + +void StateMachine::addTransition(Transition_ptr aTrans) +{ + d->_transitions.push_back(aTrans); +} + +} // of namespace simgear diff -Nru simgear-2.10.0/simgear/structure/StateMachine.hxx simgear-3.0.0/simgear/structure/StateMachine.hxx --- simgear-2.10.0/simgear/structure/StateMachine.hxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/structure/StateMachine.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,177 @@ +/* -*-c++-*- + * + * Copyright (C) 2013 James Turner + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#ifndef SIMGEAR_STATE_MACHINE_H +#define SIMGEAR_STATE_MACHINE_H + +#include +#include + +#include +#include + +// forward decls +class SGPropertyNode; +class SGBinding; +class SGCondition; + +namespace simgear +{ + +class StateMachine : public SGReferenced +{ +public: + StateMachine(); + virtual ~StateMachine(); + + class State : public SGReferenced + { + public: + virtual ~State(); + + std::string name() const; + + void addUpdateBinding(SGBinding* aBinding); + void addEntryBinding(SGBinding* aBinding); + void addExitBinding(SGBinding* aBinding); + + private: + friend class StateMachine; + + State(const std::string& name); + + void fireExitBindings(); + void fireEntryBindings(); + + void update(); + + class StatePrivate; + std::auto_ptr d; + }; + + class Transition : public SGReferenced + { + public: + virtual ~Transition(); + + std::string name() const; + + /** + * Set if the target state should automatically be excluded + * from the source state. Defaults to true, can be cleared + * to allow a state to re-enter itself + */ + void setExcludeTarget(bool aExclude); + + + /** + * The state we end in, after this transition fires + */ + State* target() const; + + /** + * Add a state in which this transition is eligible to fire + */ + void addSourceState(State* aSource); + + /** + * Specify the transition trigger condition. Takes ownership + */ + void setTriggerCondition(SGCondition* aCondition); + + + void addBinding(SGBinding* aBinding); + private: + friend class StateMachine; + + Transition(const std::string& aName, State* aTarget); + + /** + * predicate to determine if this transition can fire given a + * current state. + */ + bool applicableForState(State* aCurrent) const; + + /** + * test if the transition should fire, based on current state + */ + bool evaluate() const; + + void fireBindings(); + + class TransitionPrivate; + std::auto_ptr d; + }; + + typedef SGSharedPtr State_ptr; + typedef SGSharedPtr Transition_ptr; + + void initFromPlist(SGPropertyNode* desc, SGPropertyNode* root); + + /** + * create a state machine from a property list description + */ + static StateMachine* createFromPlist(SGPropertyNode* desc, SGPropertyNode* root); + + SGPropertyNode* root(); + + void init(); + void shutdown(); + + void update(double dt); + + State_ptr state() const; + + /** + * public API to force a change to a particular state. + * @param aOnlyIfDifferent - only make a transition if the new state is + * different from the current state. Otherwise, the existing state will + * be exited and re-entered. + */ + void changeToState(State_ptr aState, bool aOnlyIfDifferent=true); + + /// wrapper to change state by looking up a name + void changeToStateName(const std::string& aName, bool aOnlyIfDifferent=true); + + State_ptr findStateByName(const std::string& aName) const; + + State_ptr stateByIndex(unsigned int aIndex) const; + + int indexOfState(State_ptr aState) const; + + // programatic creation + State_ptr createState(const std::string& aName); + Transition_ptr createTransition(const std::string& aName, State_ptr aTarget); +private: + void addState(State_ptr aState); + void addTransition(Transition_ptr aTrans); + + void innerChangeState(State_ptr aState, Transition_ptr aTrans); + + class StateMachinePrivate; + std::auto_ptr d; +}; + +typedef SGSharedPtr StateMachine_ptr; + +} // of simgear namespace + +#endif // of SIMGEAR_STATE_MACHINE_H diff -Nru simgear-2.10.0/simgear/structure/state_machine_test.cxx simgear-3.0.0/simgear/structure/state_machine_test.cxx --- simgear-2.10.0/simgear/structure/state_machine_test.cxx 1970-01-01 00:00:00.000000000 +0000 +++ simgear-3.0.0/simgear/structure/state_machine_test.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -0,0 +1,244 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef NDEBUG +// Always enable DEBUG mode in test application, otherwise "assert" test +// statements have no effect and don't actually test anything (catch 17 ;-) ). +#undef NDEBUG +#endif + +#include + +#include +#include +#include +#include + +#include "StateMachine.hxx" + +#include +#include +#include +#include +#include +#include +#include + +using std::string; +using std::cout; +using std::cerr; +using std::endl; + +// SGCondition subclass we can trivially manipulate from test code. +class DummyCondition : public SGCondition +{ +public: + DummyCondition(): _state(false) { } + + virtual bool test() const + { + return _state; + } + + bool _state; +}; + +class DummyThing +{ +public: + DummyThing() : dummy_cmd_state(0) { } + + bool someCommand(const SGPropertyNode* arg) + { + dummy_cmd_state++; + return true; + } + + int dummy_cmd_state; +}; + +using namespace simgear; + +#define BUILD_MACHINE_1() \ + StateMachine_ptr sm(new StateMachine); \ + StateMachine::State_ptr stateA = sm->createState("a"); \ + StateMachine::State_ptr stateB = sm->createState("b"); \ + StateMachine::State_ptr stateC = sm->createState("c"); \ + \ + DummyCondition* trigger1 = new DummyCondition; \ + StateMachine::Transition_ptr t1 = sm->createTransition(">b", stateB); \ + t1->addSourceState(stateA); \ + t1->setTriggerCondition(trigger1); \ + \ + DummyCondition* trigger2 = new DummyCondition; \ + StateMachine::Transition_ptr t2 = sm->createTransition(">c", stateC); \ + t2->addSourceState(stateB); \ + t2->setTriggerCondition(trigger2); \ + \ + DummyCondition* trigger3 = new DummyCondition; \ + StateMachine::Transition_ptr t3 = sm->createTransition(">a", stateA); \ + t3->addSourceState(stateC); \ + t3->addSourceState(stateB); \ + t3->setTriggerCondition(trigger3); \ + sm->init(); + +void testBasic() +{ + BUILD_MACHINE_1(); +//////////////////////////////////////////// + COMPARE(sm->state()->name(), "a"); + + COMPARE(sm->indexOfState(stateA), 0); + COMPARE(sm->findStateByName("c"), stateC); + + sm->changeToState(stateC); + COMPARE(sm->state(), stateC); + + trigger3->_state = true; + sm->update(1.0); + COMPARE(sm->state()->name(), "a"); + trigger3->_state = false; + + trigger1->_state = true; + sm->update(1.0); + trigger1->_state = false; + COMPARE(sm->state()->name(), "b"); + + trigger3->_state = true; + sm->update(1.0); + COMPARE(sm->state()->name(), "a"); + trigger3->_state = false; + + trigger1->_state = true; + sm->update(1.0); + trigger1->_state = false; + COMPARE(sm->state()->name(), "b"); + + trigger2->_state = true; + sm->update(1.0); + trigger2->_state = false; + COMPARE(sm->state()->name(), "c"); + +////////////////////////////////////////// + COMPARE(sm->root()->getIntValue("current-index"), 2); + COMPARE(sm->root()->getStringValue("current-name"), string("c")); + + sm->root()->setStringValue("current-name", "b"); + COMPARE(sm->state()->name(), "b"); + +//////////////////////////////////////// + COMPARE(sm->findStateByName("foo"), NULL); + COMPARE(sm->indexOfState(StateMachine::State_ptr()), -1); + + COMPARE(sm->stateByIndex(1), stateB); + + try { + sm->stateByIndex(44); + VERIFY(false && "should have raised an exception"); + } catch (sg_exception& e){ + // expected! + } +} + +void testNoSourcesTransition() +{ + BUILD_MACHINE_1(); + + DummyCondition* trigger4 = new DummyCondition; + StateMachine::Transition_ptr t4 = sm->createTransition("alwaysToA", stateA); \ + t4->setTriggerCondition(trigger4); \ + sm->init(); + + COMPARE(sm->state()->name(), "a"); + trigger1->_state = true; + sm->update(1.0); + trigger1->_state = false; + COMPARE(sm->state()->name(), "b"); + + trigger4->_state = true; + sm->update(1.0); + trigger4->_state = false; + COMPARE(sm->state()->name(), "a"); +} + +void testBindings() +{ + SGCommandMgr* cmdMgr = SGCommandMgr::instance(); + DummyThing thing; + cmdMgr->addCommand("dummy", &thing, &DummyThing::someCommand); + BUILD_MACHINE_1(); + + t2->addBinding(new SGBinding("dummy")); + + stateA->addEntryBinding(new SGBinding("dummy")); + stateA->addExitBinding(new SGBinding("dummy")); + stateC->addEntryBinding(new SGBinding("dummy")); + +//////////////////////// + COMPARE(sm->state()->name(), "a"); + trigger1->_state = true; + sm->update(1.0); + trigger1->_state = false; + COMPARE(sm->state()->name(), "b"); + COMPARE(thing.dummy_cmd_state, 1); // exit state A + + trigger2->_state = true; + sm->update(1.0); + trigger2->_state = false; + COMPARE(thing.dummy_cmd_state, 3); // fire transition 2, enter state C + + thing.dummy_cmd_state = 0; + sm->changeToState(stateA); + COMPARE(thing.dummy_cmd_state, 1); // enter state A + trigger1->_state = true; + sm->update(1.0); + trigger1->_state = false; + COMPARE(thing.dummy_cmd_state, 2); // exit state A + +//////////////////////// + t3->addBinding(new SGBinding("dummy")); + t3->addBinding(new SGBinding("dummy")); + t3->addBinding(new SGBinding("dummy")); + + sm->changeToStateName("b"); + thing.dummy_cmd_state = 0; + trigger3->_state = true; + sm->update(1.0); + trigger3->_state = false; + COMPARE(thing.dummy_cmd_state, 4); // three transition bindings, enter A +} + +void testParse() +{ + const char* xml = "" + "" + "" + "one" + "" + "" + "two" + "" + ""; + + SGPropertyNode* desc = new SGPropertyNode; + readProperties(xml, strlen(xml), desc); + + SGPropertyNode_ptr root(new SGPropertyNode); + StateMachine_ptr sm = StateMachine::createFromPlist(desc, root); + + VERIFY(sm->findStateByName("one") != NULL); + VERIFY(sm->findStateByName("two") != NULL); +} + +int main(int argc, char* argv[]) +{ + testBasic(); + testBindings(); + testParse(); + testNoSourcesTransition(); + + cout << __FILE__ << ": All tests passed" << endl; + return EXIT_SUCCESS; +} + diff -Nru simgear-2.10.0/simgear/structure/subsystem_mgr.cxx simgear-3.0.0/simgear/structure/subsystem_mgr.cxx --- simgear-2.10.0/simgear/structure/subsystem_mgr.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/structure/subsystem_mgr.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -117,7 +117,6 @@ timingInfo.push_back(TimingInfo(name, SGTimeStamp::now())); } - //////////////////////////////////////////////////////////////////////// // Implementation of SGSubsystemGroup. //////////////////////////////////////////////////////////////////////// @@ -137,7 +136,7 @@ SampleStatistic timeStat; std::string name; - SGSubsystem * subsystem; + SGSharedPtr subsystem; double min_step_sec; double elapsed_sec; bool collectTimeStats; @@ -157,7 +156,7 @@ SGSubsystemGroup::~SGSubsystemGroup () { // reverse order to prevent order dependency problems - for (unsigned int i = _members.size(); i > 0; i--) + for( size_t i = _members.size(); i > 0; i-- ) { delete _members[i-1]; } @@ -166,7 +165,7 @@ void SGSubsystemGroup::init () { - for (unsigned int i = 0; i < _members.size(); i++) + for( size_t i = 0; i < _members.size(); i++ ) _members[i]->subsystem->init(); } @@ -190,14 +189,14 @@ void SGSubsystemGroup::postinit () { - for (unsigned int i = 0; i < _members.size(); i++) + for( size_t i = 0; i < _members.size(); i++ ) _members[i]->subsystem->postinit(); } void SGSubsystemGroup::reinit () { - for (unsigned int i = 0; i < _members.size(); i++) + for( size_t i = 0; i < _members.size(); i++ ) _members[i]->subsystem->reinit(); } @@ -205,7 +204,7 @@ SGSubsystemGroup::shutdown () { // reverse order to prevent order dependency problems - for (unsigned int i = _members.size(); i > 0; i--) + for( size_t i = _members.size(); i > 0; i-- ) _members[i-1]->subsystem->shutdown(); _initPosition = 0; } @@ -213,7 +212,7 @@ void SGSubsystemGroup::bind () { - for (unsigned int i = 0; i < _members.size(); i++) + for( size_t i = 0; i < _members.size(); i++ ) _members[i]->subsystem->bind(); } @@ -221,7 +220,7 @@ SGSubsystemGroup::unbind () { // reverse order to prevent order dependency problems - for (unsigned int i = _members.size(); i > 0; i--) + for( size_t i = _members.size(); i > 0; i-- ) _members[i-1]->subsystem->unbind(); } @@ -242,7 +241,7 @@ bool recordTime = (reportTimingCb != NULL); SGTimeStamp timeStamp; while (loopCount-- > 0) { - for (unsigned int i = 0; i < _members.size(); i++) + for( size_t i = 0; i < _members.size(); i++ ) { if (recordTime) timeStamp = SGTimeStamp::now(); @@ -261,7 +260,7 @@ void SGSubsystemGroup::reportTiming(void) { - for (unsigned int i = _members.size(); i > 0; i--) + for( size_t i = _members.size(); i > 0; i-- ) { _members[i-1]->reportTiming(); } @@ -270,14 +269,14 @@ void SGSubsystemGroup::suspend () { - for (unsigned int i = 0; i < _members.size(); i++) + for( size_t i = 0; i < _members.size(); i++ ) _members[i]->subsystem->suspend(); } void SGSubsystemGroup::resume () { - for (unsigned int i = 0; i < _members.size(); i++) + for( size_t i = 0; i < _members.size(); i++ ) _members[i]->subsystem->resume(); } @@ -285,7 +284,7 @@ SGSubsystemGroup::member_names() const { string_list result; - for (unsigned int i = 0; i < _members.size(); i++) + for( size_t i = 0; i < _members.size(); i++ ) result.push_back( _members[i]->name ); return result; @@ -322,12 +321,16 @@ void SGSubsystemGroup::remove_subsystem (const string &name) { - for (unsigned int i = 0; i < _members.size(); i++) { - if (name == _members[i]->name) { - _members.erase(_members.begin() + i); + MemberVec::iterator it = _members.begin(); + for (; it != _members.end(); ++it) { + if (name == (*it)->name) { + delete *it; + _members.erase(it); return; } } + + SG_LOG(SG_GENERAL, SG_WARN, "remove_subsystem: missing:" << name); } void @@ -345,7 +348,7 @@ SGSubsystemGroup::Member * SGSubsystemGroup::get_member (const string &name, bool create) { - for (unsigned int i = 0; i < _members.size(); i++) { + for( size_t i = 0; i < _members.size(); i++ ) { if (_members[i]->name == name) return _members[i]; } @@ -359,7 +362,6 @@ } - //////////////////////////////////////////////////////////////////////// // Implementation of SGSubsystemGroup::Member //////////////////////////////////////////////////////////////////////// @@ -382,7 +384,6 @@ SGSubsystemGroup::Member::~Member () { - delete subsystem; } void @@ -529,36 +530,33 @@ SGSubsystemMgr::add (const char * name, SGSubsystem * subsystem, GroupType group, double min_time_sec) { - SG_LOG(SG_GENERAL, SG_INFO, "Adding subsystem " << name); + SG_LOG(SG_GENERAL, SG_DEBUG, "Adding subsystem " << name); get_group(group)->set_subsystem(name, subsystem, min_time_sec); if (_subsystem_map.find(name) != _subsystem_map.end()) { SG_LOG(SG_GENERAL, SG_ALERT, "Adding duplicate subsystem " << name); - throw sg_exception("duplicate subsystem"); + throw sg_exception("duplicate subsystem:" + std::string(name)); } _subsystem_map[name] = subsystem; } -SGSubsystem* +void SGSubsystemMgr::remove(const char* name) { SubsystemDict::iterator s =_subsystem_map.find(name); if (s == _subsystem_map.end()) { - return NULL; + return; } - SGSubsystem* sub = s->second; _subsystem_map.erase(s); // tedious part - we don't know which group the subsystem belongs too for (int i = 0; i < MAX_GROUPS; i++) { - if (_groups[i]->get_subsystem(name) == sub) { + if (_groups[i]->get_subsystem(name) != NULL) { _groups[i]->remove_subsystem(name); break; } } // of groups iteration - - return sub; } diff -Nru simgear-2.10.0/simgear/structure/subsystem_mgr.hxx simgear-3.0.0/simgear/structure/subsystem_mgr.hxx --- simgear-2.10.0/simgear/structure/subsystem_mgr.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/structure/subsystem_mgr.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -284,7 +284,8 @@ static void* reportTimingUserData; }; - +typedef SGSharedPtr SGSubsystemRef; + /** * A group of FlightGear subsystems. @@ -332,7 +333,8 @@ class Member; Member* get_member (const std::string &name, bool create = false); - std::vector _members; + typedef std::vector MemberVec; + MemberVec _members; double _fixedUpdateTime; double _updateTimeRemainder; @@ -401,11 +403,11 @@ * remove a subsystem, and return a pointer to it. * returns NULL if the subsystem was not found. */ - virtual SGSubsystem* remove(const char* name); + virtual void remove(const char* name); virtual SGSubsystemGroup * get_group (GroupType group); - virtual SGSubsystem * get_subsystem(const std::string &name) const; + virtual SGSubsystem* get_subsystem(const std::string &name) const; void reportTiming(); void setReportTimingCb(void* userData,SGSubsystemTimingCb cb) {reportTimingCb = cb;reportTimingUserData = userData;} @@ -414,6 +416,7 @@ SGSubsystemGroup* _groups[MAX_GROUPS]; unsigned int _initPosition; + // non-owning reference typedef std::map SubsystemDict; SubsystemDict _subsystem_map; }; diff -Nru simgear-2.10.0/simgear/threads/SGQueue.hxx simgear-3.0.0/simgear/threads/SGQueue.hxx --- simgear-2.10.0/simgear/threads/SGQueue.hxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/threads/SGQueue.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -386,6 +386,11 @@ return this->queue.size(); } + void waitOnNotEmpty() { + SGGuard g(mutex); + while (this->queue.empty()) + not_empty.wait(mutex); + } private: /** diff -Nru simgear-2.10.0/simgear/timing/lowleveltime.cxx simgear-3.0.0/simgear/timing/lowleveltime.cxx --- simgear-2.10.0/simgear/timing/lowleveltime.cxx 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/timing/lowleveltime.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -1134,3 +1134,24 @@ return strncpy (p, string, needed); } + +time_t sgGMTime() +{ + // this was created to fix: + // https://code.google.com/p/flightgear-bugs/issues/detail?id=1207 + // however applying the code on Unix causes bug: + // https://code.google.com/p/flightgear-bugs/issues/detail?id=1301 + // One solution would be to deinfe our own 'timegm' as suggested here: + // http://linux.die.net/man/3/timegm + // but for the moment we'll assume time(0) on Unix is UTC, and hence we + // return it directly. + + time_t now_sec = time(0); +#if defined(SG_WINDOWS) + struct tm now; + now = *gmtime(&now_sec); + return mktime(&now); +#else + return now_sec; +#endif +} diff -Nru simgear-2.10.0/simgear/timing/lowleveltime.h simgear-3.0.0/simgear/timing/lowleveltime.h --- simgear-2.10.0/simgear/timing/lowleveltime.h 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/timing/lowleveltime.h 2014-02-15 00:04:11.000000000 +0000 @@ -41,6 +41,11 @@ /* adapted from */ struct tm * fgLocaltime (const time_t *t, const char *tzName); +/* version of time() which returns a value in GMT/UTC, without + any timezone adjustment. Necessary on Windows where calling time() + returns a value in the local time-zone. */ +time_t sgGMTime(); + /* Prototype for the internal function to get information based on TZ. */ extern struct tm *fgtz_convert (const time_t *t, int use_localtime, struct tm *tp, const char *tzName); diff -Nru simgear-2.10.0/simgear/timing/sg_time.cxx simgear-3.0.0/simgear/timing/sg_time.cxx --- simgear-2.10.0/simgear/timing/sg_time.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/timing/sg_time.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -151,20 +151,12 @@ { time_t start_gmt, now; double diff, part, days, hours, lstTmp; - char tbuf[64]; now = cur_time; start_gmt = sgTimeGetGMT(gmt->tm_year, 2, 21, 12, 0, 0); - SG_LOG( SG_EVENT, SG_DEBUG, " COURSE: GMT = " - << sgTimeFormatTime(gmt, tbuf) ); - SG_LOG( SG_EVENT, SG_DEBUG, " March 21 noon (GMT) = " << start_gmt ); - diff = (now - start_gmt) / (3600.0 * 24.0); - SG_LOG( SG_EVENT, SG_DEBUG, - " Time since 3/21/" << gmt->tm_year << " GMT = " << diff ); - part = fmod(diff, 1.0); days = diff - part; hours = gmt->tm_hour + gmt->tm_min/60.0 + gmt->tm_sec/3600.0; @@ -174,11 +166,7 @@ while ( lstTmp < 0.0 ) { lstTmp += 24.0; } - - SG_LOG( SG_EVENT, SG_DEBUG, - " days = " << days << " hours = " << hours << " lon = " - << lng << " lst = " << lstTmp ); - + return lstTmp; } @@ -205,19 +193,10 @@ } else { cur_time = time(NULL) + warp; } - SG_LOG( SG_EVENT, SG_DEBUG, - " Current Unix calendar time = " << cur_time - << " warp = " << warp ); // get GMT break down for current time memcpy( gmt, gmtime(&cur_time), sizeof(tm) ); - SG_LOG( SG_EVENT, SG_DEBUG, - " Current GMT = " << gmt->tm_mon+1 << "/" - << gmt->tm_mday << "/" << (1900 + gmt->tm_year) << " " - << gmt->tm_hour << ":" << gmt->tm_min << ":" - << gmt->tm_sec ); - // calculate modified Julian date starting with current mjd = sgTimeCurrentMJD( ct, warp ); @@ -227,7 +206,6 @@ // convert "back" to Julian date + partial day (as a fraction of one) jd = mjd + MJD0; - SG_LOG( SG_EVENT, SG_DEBUG, " Current Julian Date = " << jd ); // printf(" Current Longitude = %.3f\n", FG_Longitude * SGD_RADIANS_TO_DEGREES); @@ -249,13 +227,6 @@ lst = sidereal_course( cur_time, gmt, -location.getLongitudeDeg() ) + gst_diff; } - - SG_LOG( SG_EVENT, SG_DEBUG, - " Current lon=0.00 Sidereal Time = " << gst ); - SG_LOG( SG_EVENT, SG_DEBUG, - " Current LOCAL Sidereal Time = " << lst << " (" - << sidereal_precise( mjd, -location.getLongitudeDeg() ) - << ") (diff = " << gst_diff << ")" ); } @@ -354,17 +325,9 @@ } else { cur_time = time(NULL) + warp; } - SG_LOG( SG_EVENT, SG_DEBUG, - " Current Unix calendar time = " << cur_time - << " warp = " << warp ); // get GMT break down for current time memcpy( gmt, gmtime(&cur_time), sizeof(tm) ); - SG_LOG( SG_EVENT, SG_DEBUG, - " Current GMT = " << gmt->tm_mon+1 << "/" - << gmt->tm_mday << "/" << (1900 + gmt->tm_year) << " " - << gmt->tm_hour << ":" << gmt->tm_min << ":" - << gmt->tm_sec ); // calculate modified Julian date // t->mjd = cal_mjd ((int)(t->gmt->tm_mon+1), (double)t->gmt->tm_mday, @@ -389,8 +352,6 @@ x /= 3600.0; gst = (1.0/SIDRATE)*hr + x; - SG_LOG( SG_EVENT, SG_DEBUG, " gst => " << gst ); - return gst; } diff -Nru simgear-2.10.0/simgear/xml/ascii.h simgear-3.0.0/simgear/xml/ascii.h --- simgear-2.10.0/simgear/xml/ascii.h 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/ascii.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,92 +0,0 @@ -/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd - See the file COPYING for copying permission. -*/ - -#define ASCII_A 0x41 -#define ASCII_B 0x42 -#define ASCII_C 0x43 -#define ASCII_D 0x44 -#define ASCII_E 0x45 -#define ASCII_F 0x46 -#define ASCII_G 0x47 -#define ASCII_H 0x48 -#define ASCII_I 0x49 -#define ASCII_J 0x4A -#define ASCII_K 0x4B -#define ASCII_L 0x4C -#define ASCII_M 0x4D -#define ASCII_N 0x4E -#define ASCII_O 0x4F -#define ASCII_P 0x50 -#define ASCII_Q 0x51 -#define ASCII_R 0x52 -#define ASCII_S 0x53 -#define ASCII_T 0x54 -#define ASCII_U 0x55 -#define ASCII_V 0x56 -#define ASCII_W 0x57 -#define ASCII_X 0x58 -#define ASCII_Y 0x59 -#define ASCII_Z 0x5A - -#define ASCII_a 0x61 -#define ASCII_b 0x62 -#define ASCII_c 0x63 -#define ASCII_d 0x64 -#define ASCII_e 0x65 -#define ASCII_f 0x66 -#define ASCII_g 0x67 -#define ASCII_h 0x68 -#define ASCII_i 0x69 -#define ASCII_j 0x6A -#define ASCII_k 0x6B -#define ASCII_l 0x6C -#define ASCII_m 0x6D -#define ASCII_n 0x6E -#define ASCII_o 0x6F -#define ASCII_p 0x70 -#define ASCII_q 0x71 -#define ASCII_r 0x72 -#define ASCII_s 0x73 -#define ASCII_t 0x74 -#define ASCII_u 0x75 -#define ASCII_v 0x76 -#define ASCII_w 0x77 -#define ASCII_x 0x78 -#define ASCII_y 0x79 -#define ASCII_z 0x7A - -#define ASCII_0 0x30 -#define ASCII_1 0x31 -#define ASCII_2 0x32 -#define ASCII_3 0x33 -#define ASCII_4 0x34 -#define ASCII_5 0x35 -#define ASCII_6 0x36 -#define ASCII_7 0x37 -#define ASCII_8 0x38 -#define ASCII_9 0x39 - -#define ASCII_TAB 0x09 -#define ASCII_SPACE 0x20 -#define ASCII_EXCL 0x21 -#define ASCII_QUOT 0x22 -#define ASCII_AMP 0x26 -#define ASCII_APOS 0x27 -#define ASCII_MINUS 0x2D -#define ASCII_PERIOD 0x2E -#define ASCII_COLON 0x3A -#define ASCII_SEMI 0x3B -#define ASCII_LT 0x3C -#define ASCII_EQUALS 0x3D -#define ASCII_GT 0x3E -#define ASCII_LSQB 0x5B -#define ASCII_RSQB 0x5D -#define ASCII_UNDERSCORE 0x5F -#define ASCII_LPAREN 0x28 -#define ASCII_RPAREN 0x29 -#define ASCII_FF 0x0C -#define ASCII_SLASH 0x2F -#define ASCII_HASH 0x23 -#define ASCII_PIPE 0x7C -#define ASCII_COMMA 0x2C diff -Nru simgear-2.10.0/simgear/xml/asciitab.h simgear-3.0.0/simgear/xml/asciitab.h --- simgear-2.10.0/simgear/xml/asciitab.h 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/xml/asciitab.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (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.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, -/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML, -/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, -/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, -/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, -/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, -/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, -/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, -/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, -/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, -/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, -/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, -/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, -/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, -/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, -/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, -/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, -/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff -Nru simgear-2.10.0/simgear/xml/CMakeLists.txt simgear-3.0.0/simgear/xml/CMakeLists.txt --- simgear-2.10.0/simgear/xml/CMakeLists.txt 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/xml/CMakeLists.txt 2014-02-15 00:04:11.000000000 +0000 @@ -10,28 +10,4 @@ easyxml.cxx ) -if (NOT SYSTEM_EXPAT) - list(APPEND SOURCES - asciitab.h - hashtable.h - iasciitab.h - latin1tab.h - nametab.h - utf8tab.h - xmldef.h - xmlparse.h - xmlrole.h - xmltok.h - xmltok_impl.h - hashtable.c - xmlparse.c - xmlrole.c - xmltok.c - internal.h - ascii.h - expat.h - expat_external.h - ) -endif() - simgear_component(xml xml "${SOURCES}" "${HEADERS}") diff -Nru simgear-2.10.0/simgear/xml/easyxml.cxx simgear-3.0.0/simgear/xml/easyxml.cxx --- simgear-2.10.0/simgear/xml/easyxml.cxx 2013-01-28 17:02:28.000000000 +0000 +++ simgear-3.0.0/simgear/xml/easyxml.cxx 2014-02-15 00:04:11.000000000 +0000 @@ -17,14 +17,15 @@ #ifdef SYSTEM_EXPAT # include #else -# include "xmlparse.h" +# include "sg_expat.h" #endif #include #include using std::ifstream; - +using std::istream; +using std::string; //////////////////////////////////////////////////////////////////////// @@ -136,24 +137,20 @@ } - +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void XMLVisitor::savePosition(void) +{ + if (parser) { + column = XML_GetCurrentColumnNumber(parser); + line = XML_GetCurrentLineNumber(parser); + } +} + //////////////////////////////////////////////////////////////////////// // Attribute list wrapper for Expat. //////////////////////////////////////////////////////////////////////// -class ExpatAtts : public XMLAttributes -{ -public: - ExpatAtts (const char ** atts) : _atts(atts) {} - - virtual int size () const; - virtual const char * getName (int i) const; - virtual const char * getValue (int i) const; - -private: - const char ** _atts; -}; - int ExpatAtts::size () const { @@ -175,6 +172,11 @@ return _atts[i*2+1]; } +const char * +ExpatAtts::getValue (const char * name) const +{ + return XMLAttributes::getValue(name); +} //////////////////////////////////////////////////////////////////////// @@ -186,18 +188,21 @@ static void start_element (void * userData, const char * name, const char ** atts) { + VISITOR.savePosition(); VISITOR.startElement(name, ExpatAtts(atts)); } static void end_element (void * userData, const char * name) { + VISITOR.savePosition(); VISITOR.endElement(name); } static void character_data (void * userData, const char * s, int len) { + VISITOR.savePosition(); VISITOR.data(s, len); } @@ -206,6 +211,7 @@ const char * target, const char * data) { + VISITOR.savePosition(); VISITOR.pi(target, data); } @@ -226,6 +232,8 @@ XML_SetCharacterDataHandler(parser, character_data); XML_SetProcessingInstructionHandler(parser, processing_instruction); + visitor.setParser(parser); + visitor.setPath(path); visitor.startXML(); char buf[16384]; @@ -238,6 +246,7 @@ XML_GetCurrentLineNumber(parser), XML_GetCurrentColumnNumber(parser)), "SimGear XML Parser"); + visitor.setParser(0); XML_ParserFree(parser); throw ex; } @@ -249,6 +258,7 @@ XML_GetCurrentLineNumber(parser), XML_GetCurrentColumnNumber(parser)), "SimGear XML Parser"); + visitor.setParser(0); XML_ParserFree(parser); throw ex; } @@ -262,10 +272,12 @@ XML_GetCurrentLineNumber(parser), XML_GetCurrentColumnNumber(parser)), "SimGear XML Parser"); + visitor.setParser(0); XML_ParserFree(parser); throw ex; } + visitor.setParser(0); XML_ParserFree(parser); visitor.endXML(); } diff -Nru simgear-2.10.0/simgear/xml/easyxml.hxx simgear-3.0.0/simgear/xml/easyxml.hxx --- simgear-2.10.0/simgear/xml/easyxml.hxx 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/xml/easyxml.hxx 2014-02-15 00:04:11.000000000 +0000 @@ -15,10 +15,7 @@ #include #include -using std::istream; -using std::string; -using std::vector; - +typedef struct XML_ParserStruct* XML_Parser; /** * Interface for XML attributes. @@ -220,7 +217,25 @@ virtual void setValue (const char * name, const char * value); private: - vector _atts; + std::vector _atts; +}; + +//////////////////////////////////////////////////////////////////////// +// Attribute list wrapper for Expat. +//////////////////////////////////////////////////////////////////////// + +class ExpatAtts : public XMLAttributes +{ +public: + ExpatAtts (const char ** atts) : _atts(atts) {} + + virtual int size () const; + virtual const char * getName (int i) const; + virtual const char * getValue (int i) const; + + virtual const char * getValue (const char * name) const; +private: + const char ** _atts; }; @@ -238,6 +253,8 @@ class XMLVisitor { public: + /// Constructor + XMLVisitor() : parser(0), line(-1), column(-1) {} /** * Virtual destructor. @@ -354,6 +371,81 @@ * the warning. */ virtual void warning (const char * message, int line, int column) {} + + /** Set the path to the file that is parsed. + * + * This method will be called to store the path to the parsed file. Note that + * the XML parser makes no use of this copy of the path. The intent is + * to be capable of refering to the path to the parsed file if needed. + * + * @param _path The path to the parsed file. + * @see #getPath + */ + void setPath(const std::string& _path) { path = _path; } + + /** Get the path to the parsed file. + * + * This method will be called if the application needs to access the path to + * the parsed file. This information is typically needed if an error is found + * so the file where it occurred can be retrieved to help the user locate the + * error. + * + * @return the path to the parsed file. + * @see #setPath + */ + const std::string& getPath(void) const { return path; } + + /** Save the current position in the parsed file. + * + * This method will be called to save the position at which the file is + * currently parsed. Note that the XML parser makes no use of that + * information. The intent is to be capable of refering to the position in + * the parsed file if needed. + * + * @see #getColumn + * @see #getLine + */ + void savePosition(void); + + /** Get the saved column number in the parsed file. + * + * This method will be called if the application needs to get the column + * number that has been saved during the last call to savePosition(). This + * information is typically needed if an error is found so the position at + * which it occurred can be retrieved to help the user locate the error. + * + * @return the save column number. + * @see #savePosition + */ + int getColumn(void) const { return column; } + + /** Get the saved line number in the parsed file. + * + * This method will be called if the application needs to get the line + * number that has been saved during the last call to savePosition(). This + * information is typically needed if an error is found so the position at + * which it occurred can be retrieved to help the user locate the error. + * + * @return the save line number. + * @see #savePosition + */ + int getLine(void) const { return line; } + + /** Set the XML parser. + * + * This method will be called so the #XMLVisitor instance can internally use + * the XML parser for its housekeeping. The intent is that #XMLVisitor will + * only call the reporting functions of the XML parser and will not interfer + * with the XML parser current state. Doing otherwise will result in an + * unpredictable behavior of the XML parser. + * + * @param _parser the XML parser + */ + void setParser(XML_Parser _parser) { parser = _parser; } +private: + XML_Parser parser; + std::string path; + int line, column; }; @@ -376,8 +468,8 @@ * is a problem reading the file. * @see XMLVisitor */ -extern void readXML (istream &input, XMLVisitor &visitor, - const string &path=""); +extern void readXML (std::istream &input, XMLVisitor &visitor, + const std::string &path=""); /** @@ -398,7 +490,7 @@ * is a problem reading the file. * @see XMLVisitor */ -extern void readXML (const string &path, XMLVisitor &visitor); +extern void readXML (const std::string &path, XMLVisitor &visitor); /** diff -Nru simgear-2.10.0/simgear/xml/expat_config_cmake.in simgear-3.0.0/simgear/xml/expat_config_cmake.in --- simgear-2.10.0/simgear/xml/expat_config_cmake.in 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/expat_config_cmake.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,41 +0,0 @@ - -#ifndef EXPAT_CONFIG_H -#define EXPAT_CONFIG_H - -#cmakedefine HAVE_WINDOWS_H - -#ifdef HAVE_WINDOWS_H - #define WIN32_LEAN_AND_MEAN - #include - #undef WIN32_LEAN_AND_MEAN -#endif - -/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ -#define BYTEORDER 1234 - -/* Define to 1 if you have the `bcopy' function. */ -#cmakedefine HAVE_BCOPY - -/* Define to 1 if you have the `memmove' function. */ -#define HAVE_MEMMOVE - -/* Define to 1 if you have a working `mmap' system call. */ -#cmakedefine HAVE_MMAP - -/* Define to 1 if you have the header file. */ -#cmakedefine HAVE_UNISTD_H - -/* whether byteorder is bigendian */ -#undef WORDS_BIGENDIAN - -/* Define to specify how much context to retain around the current parse - point. */ -#define XML_CONTEXT_BYTES 1024 - -/* Define to make parameter entity parsing functionality available. */ -#define XML_DTD - -/* Define to make XML Namespaces functionality available. */ -#define XML_NS - -#endif /* ifndef EXPAT_CONFIG_H */ diff -Nru simgear-2.10.0/simgear/xml/Expat.COPYING simgear-3.0.0/simgear/xml/Expat.COPYING --- simgear-2.10.0/simgear/xml/Expat.COPYING 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/Expat.COPYING 1970-01-01 00:00:00.000000000 +0000 @@ -1,22 +0,0 @@ -Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd - and Clark Cooper -Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Expat maintainers. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff -Nru simgear-2.10.0/simgear/xml/expat_external.h simgear-3.0.0/simgear/xml/expat_external.h --- simgear-2.10.0/simgear/xml/expat_external.h 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/expat_external.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd - See the file COPYING for copying permission. -*/ - -#ifndef Expat_External_INCLUDED -#define Expat_External_INCLUDED 1 - -/* External API definitions */ - -#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__) -#define XML_USE_MSC_EXTENSIONS 1 -#endif - -/* Expat tries very hard to make the API boundary very specifically - defined. There are two macros defined to control this boundary; - each of these can be defined before including this header to - achieve some different behavior, but doing so it not recommended or - tested frequently. - - XMLCALL - The calling convention to use for all calls across the - "library boundary." This will default to cdecl, and - try really hard to tell the compiler that's what we - want. - - XMLIMPORT - Whatever magic is needed to note that a function is - to be imported from a dynamically loaded library - (.dll, .so, or .sl, depending on your platform). - - The XMLCALL macro was added in Expat 1.95.7. The only one which is - expected to be directly useful in client code is XMLCALL. - - Note that on at least some Unix versions, the Expat library must be - compiled with the cdecl calling convention as the default since - system headers may assume the cdecl convention. -*/ -#ifndef XMLCALL -#if defined(_MSC_VER) -#define XMLCALL __cdecl -#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER) -#define XMLCALL __attribute__((cdecl)) -#else -/* For any platform which uses this definition and supports more than - one calling convention, we need to extend this definition to - declare the convention used on that platform, if it's possible to - do so. - - If this is the case for your platform, please file a bug report - with information on how to identify your platform via the C - pre-processor and how to specify the same calling convention as the - platform's malloc() implementation. -*/ -#define XMLCALL -#endif -#endif /* not defined XMLCALL */ - - -#if !defined(XML_STATIC) && !defined(XMLIMPORT) -#ifndef XML_BUILDING_EXPAT -/* using Expat from an application */ - -#ifdef XML_USE_MSC_EXTENSIONS -#define XMLIMPORT __declspec(dllimport) -#endif - -#endif -#endif /* not defined XML_STATIC */ - - -/* If we didn't define it above, define it away: */ -#ifndef XMLIMPORT -#define XMLIMPORT -#endif - - -#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef XML_UNICODE_WCHAR_T -#define XML_UNICODE -#endif - -#ifdef XML_UNICODE /* Information is UTF-16 encoded. */ -#ifdef XML_UNICODE_WCHAR_T -typedef wchar_t XML_Char; -typedef wchar_t XML_LChar; -#else -typedef unsigned short XML_Char; -typedef char XML_LChar; -#endif /* XML_UNICODE_WCHAR_T */ -#else /* Information is UTF-8 encoded. */ -typedef char XML_Char; -typedef char XML_LChar; -#endif /* XML_UNICODE */ - -#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */ -#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400 -typedef __int64 XML_Index; -typedef unsigned __int64 XML_Size; -#else -typedef long long XML_Index; -typedef unsigned long long XML_Size; -#endif -#else -typedef long XML_Index; -typedef unsigned long XML_Size; -#endif /* XML_LARGE_SIZE */ - -#ifdef __cplusplus -} -#endif - -#endif /* not Expat_External_INCLUDED */ diff -Nru simgear-2.10.0/simgear/xml/expat.h simgear-3.0.0/simgear/xml/expat.h --- simgear-2.10.0/simgear/xml/expat.h 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/expat.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,1047 +0,0 @@ -/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd - See the file COPYING for copying permission. -*/ - -#ifndef Expat_INCLUDED -#define Expat_INCLUDED 1 - -#ifdef __VMS -/* 0 1 2 3 0 1 2 3 - 1234567890123456789012345678901 1234567890123456789012345678901 */ -#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler -#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler -#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler -#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg -#endif - -#include -#include "expat_external.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct XML_ParserStruct; -typedef struct XML_ParserStruct *XML_Parser; - -/* Should this be defined using stdbool.h when C99 is available? */ -typedef unsigned char XML_Bool; -#define XML_TRUE ((XML_Bool) 1) -#define XML_FALSE ((XML_Bool) 0) - -/* The XML_Status enum gives the possible return values for several - API functions. The preprocessor #defines are included so this - stanza can be added to code that still needs to support older - versions of Expat 1.95.x: - - #ifndef XML_STATUS_OK - #define XML_STATUS_OK 1 - #define XML_STATUS_ERROR 0 - #endif - - Otherwise, the #define hackery is quite ugly and would have been - dropped. -*/ -enum XML_Status { - XML_STATUS_ERROR = 0, -#define XML_STATUS_ERROR XML_STATUS_ERROR - XML_STATUS_OK = 1, -#define XML_STATUS_OK XML_STATUS_OK - XML_STATUS_SUSPENDED = 2 -#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED -}; - -enum XML_Error { - XML_ERROR_NONE, - XML_ERROR_NO_MEMORY, - XML_ERROR_SYNTAX, - XML_ERROR_NO_ELEMENTS, - XML_ERROR_INVALID_TOKEN, - XML_ERROR_UNCLOSED_TOKEN, - XML_ERROR_PARTIAL_CHAR, - XML_ERROR_TAG_MISMATCH, - XML_ERROR_DUPLICATE_ATTRIBUTE, - XML_ERROR_JUNK_AFTER_DOC_ELEMENT, - XML_ERROR_PARAM_ENTITY_REF, - XML_ERROR_UNDEFINED_ENTITY, - XML_ERROR_RECURSIVE_ENTITY_REF, - XML_ERROR_ASYNC_ENTITY, - XML_ERROR_BAD_CHAR_REF, - XML_ERROR_BINARY_ENTITY_REF, - XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, - XML_ERROR_MISPLACED_XML_PI, - XML_ERROR_UNKNOWN_ENCODING, - XML_ERROR_INCORRECT_ENCODING, - XML_ERROR_UNCLOSED_CDATA_SECTION, - XML_ERROR_EXTERNAL_ENTITY_HANDLING, - XML_ERROR_NOT_STANDALONE, - XML_ERROR_UNEXPECTED_STATE, - XML_ERROR_ENTITY_DECLARED_IN_PE, - XML_ERROR_FEATURE_REQUIRES_XML_DTD, - XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING, - /* Added in 1.95.7. */ - XML_ERROR_UNBOUND_PREFIX, - /* Added in 1.95.8. */ - XML_ERROR_UNDECLARING_PREFIX, - XML_ERROR_INCOMPLETE_PE, - XML_ERROR_XML_DECL, - XML_ERROR_TEXT_DECL, - XML_ERROR_PUBLICID, - XML_ERROR_SUSPENDED, - XML_ERROR_NOT_SUSPENDED, - XML_ERROR_ABORTED, - XML_ERROR_FINISHED, - XML_ERROR_SUSPEND_PE, - /* Added in 2.0. */ - XML_ERROR_RESERVED_PREFIX_XML, - XML_ERROR_RESERVED_PREFIX_XMLNS, - XML_ERROR_RESERVED_NAMESPACE_URI -}; - -enum XML_Content_Type { - XML_CTYPE_EMPTY = 1, - XML_CTYPE_ANY, - XML_CTYPE_MIXED, - XML_CTYPE_NAME, - XML_CTYPE_CHOICE, - XML_CTYPE_SEQ -}; - -enum XML_Content_Quant { - XML_CQUANT_NONE, - XML_CQUANT_OPT, - XML_CQUANT_REP, - XML_CQUANT_PLUS -}; - -/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be - XML_CQUANT_NONE, and the other fields will be zero or NULL. - If type == XML_CTYPE_MIXED, then quant will be NONE or REP and - numchildren will contain number of elements that may be mixed in - and children point to an array of XML_Content cells that will be - all of XML_CTYPE_NAME type with no quantification. - - If type == XML_CTYPE_NAME, then the name points to the name, and - the numchildren field will be zero and children will be NULL. The - quant fields indicates any quantifiers placed on the name. - - CHOICE and SEQ will have name NULL, the number of children in - numchildren and children will point, recursively, to an array - of XML_Content cells. - - The EMPTY, ANY, and MIXED types will only occur at top level. -*/ - -typedef struct XML_cp XML_Content; - -struct XML_cp { - enum XML_Content_Type type; - enum XML_Content_Quant quant; - XML_Char * name; - unsigned int numchildren; - XML_Content * children; -}; - - -/* This is called for an element declaration. See above for - description of the model argument. It's the caller's responsibility - to free model when finished with it. -*/ -typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData, - const XML_Char *name, - XML_Content *model); - -XMLPARSEAPI(void) -XML_SetElementDeclHandler(XML_Parser parser, - XML_ElementDeclHandler eldecl); - -/* The Attlist declaration handler is called for *each* attribute. So - a single Attlist declaration with multiple attributes declared will - generate multiple calls to this handler. The "default" parameter - may be NULL in the case of the "#IMPLIED" or "#REQUIRED" - keyword. The "isrequired" parameter will be true and the default - value will be NULL in the case of "#REQUIRED". If "isrequired" is - true and default is non-NULL, then this is a "#FIXED" default. -*/ -typedef void (XMLCALL *XML_AttlistDeclHandler) ( - void *userData, - const XML_Char *elname, - const XML_Char *attname, - const XML_Char *att_type, - const XML_Char *dflt, - int isrequired); - -XMLPARSEAPI(void) -XML_SetAttlistDeclHandler(XML_Parser parser, - XML_AttlistDeclHandler attdecl); - -/* The XML declaration handler is called for *both* XML declarations - and text declarations. The way to distinguish is that the version - parameter will be NULL for text declarations. The encoding - parameter may be NULL for XML declarations. The standalone - parameter will be -1, 0, or 1 indicating respectively that there - was no standalone parameter in the declaration, that it was given - as no, or that it was given as yes. -*/ -typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData, - const XML_Char *version, - const XML_Char *encoding, - int standalone); - -XMLPARSEAPI(void) -XML_SetXmlDeclHandler(XML_Parser parser, - XML_XmlDeclHandler xmldecl); - - -typedef struct { - void *(*malloc_fcn)(size_t size); - void *(*realloc_fcn)(void *ptr, size_t size); - void (*free_fcn)(void *ptr); -} XML_Memory_Handling_Suite; - -/* Constructs a new parser; encoding is the encoding specified by the - external protocol or NULL if there is none specified. -*/ -XMLPARSEAPI(XML_Parser) -XML_ParserCreate(const XML_Char *encoding); - -/* Constructs a new parser and namespace processor. Element type - names and attribute names that belong to a namespace will be - expanded; unprefixed attribute names are never expanded; unprefixed - element type names are expanded only if there is a default - namespace. The expanded name is the concatenation of the namespace - URI, the namespace separator character, and the local part of the - name. If the namespace separator is '\0' then the namespace URI - and the local part will be concatenated without any separator. - It is a programming error to use the separator '\0' with namespace - triplets (see XML_SetReturnNSTriplet). -*/ -XMLPARSEAPI(XML_Parser) -XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); - - -/* Constructs a new parser using the memory management suite referred to - by memsuite. If memsuite is NULL, then use the standard library memory - suite. If namespaceSeparator is non-NULL it creates a parser with - namespace processing as described above. The character pointed at - will serve as the namespace separator. - - All further memory operations used for the created parser will come from - the given suite. -*/ -XMLPARSEAPI(XML_Parser) -XML_ParserCreate_MM(const XML_Char *encoding, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *namespaceSeparator); - -/* Prepare a parser object to be re-used. This is particularly - valuable when memory allocation overhead is disproportionatly high, - such as when a large number of small documnents need to be parsed. - All handlers are cleared from the parser, except for the - unknownEncodingHandler. The parser's external state is re-initialized - except for the values of ns and ns_triplets. - - Added in Expat 1.95.3. -*/ -XMLPARSEAPI(XML_Bool) -XML_ParserReset(XML_Parser parser, const XML_Char *encoding); - -/* atts is array of name/value pairs, terminated by 0; - names and values are 0 terminated. -*/ -typedef void (XMLCALL *XML_StartElementHandler) (void *userData, - const XML_Char *name, - const XML_Char **atts); - -typedef void (XMLCALL *XML_EndElementHandler) (void *userData, - const XML_Char *name); - - -/* s is not 0 terminated. */ -typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData, - const XML_Char *s, - int len); - -/* target and data are 0 terminated */ -typedef void (XMLCALL *XML_ProcessingInstructionHandler) ( - void *userData, - const XML_Char *target, - const XML_Char *data); - -/* data is 0 terminated */ -typedef void (XMLCALL *XML_CommentHandler) (void *userData, - const XML_Char *data); - -typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData); -typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData); - -/* This is called for any characters in the XML document for which - there is no applicable handler. This includes both characters that - are part of markup which is of a kind that is not reported - (comments, markup declarations), or characters that are part of a - construct which could be reported but for which no handler has been - supplied. The characters are passed exactly as they were in the XML - document except that they will be encoded in UTF-8 or UTF-16. - Line boundaries are not normalized. Note that a byte order mark - character is not passed to the default handler. There are no - guarantees about how characters are divided between calls to the - default handler: for example, a comment might be split between - multiple calls. -*/ -typedef void (XMLCALL *XML_DefaultHandler) (void *userData, - const XML_Char *s, - int len); - -/* This is called for the start of the DOCTYPE declaration, before - any DTD or internal subset is parsed. -*/ -typedef void (XMLCALL *XML_StartDoctypeDeclHandler) ( - void *userData, - const XML_Char *doctypeName, - const XML_Char *sysid, - const XML_Char *pubid, - int has_internal_subset); - -/* This is called for the start of the DOCTYPE declaration when the - closing > is encountered, but after processing any external - subset. -*/ -typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData); - -/* This is called for entity declarations. The is_parameter_entity - argument will be non-zero if the entity is a parameter entity, zero - otherwise. - - For internal entities (), value will - be non-NULL and systemId, publicID, and notationName will be NULL. - The value string is NOT nul-terminated; the length is provided in - the value_length argument. Since it is legal to have zero-length - values, do not use this argument to test for internal entities. - - For external entities, value will be NULL and systemId will be - non-NULL. The publicId argument will be NULL unless a public - identifier was provided. The notationName argument will have a - non-NULL value only for unparsed entity declarations. - - Note that is_parameter_entity can't be changed to XML_Bool, since - that would break binary compatibility. -*/ -typedef void (XMLCALL *XML_EntityDeclHandler) ( - void *userData, - const XML_Char *entityName, - int is_parameter_entity, - const XML_Char *value, - int value_length, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId, - const XML_Char *notationName); - -XMLPARSEAPI(void) -XML_SetEntityDeclHandler(XML_Parser parser, - XML_EntityDeclHandler handler); - -/* OBSOLETE -- OBSOLETE -- OBSOLETE - This handler has been superceded by the EntityDeclHandler above. - It is provided here for backward compatibility. - - This is called for a declaration of an unparsed (NDATA) entity. - The base argument is whatever was set by XML_SetBase. The - entityName, systemId and notationName arguments will never be - NULL. The other arguments may be. -*/ -typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) ( - void *userData, - const XML_Char *entityName, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId, - const XML_Char *notationName); - -/* This is called for a declaration of notation. The base argument is - whatever was set by XML_SetBase. The notationName will never be - NULL. The other arguments can be. -*/ -typedef void (XMLCALL *XML_NotationDeclHandler) ( - void *userData, - const XML_Char *notationName, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId); - -/* When namespace processing is enabled, these are called once for - each namespace declaration. The call to the start and end element - handlers occur between the calls to the start and end namespace - declaration handlers. For an xmlns attribute, prefix will be - NULL. For an xmlns="" attribute, uri will be NULL. -*/ -typedef void (XMLCALL *XML_StartNamespaceDeclHandler) ( - void *userData, - const XML_Char *prefix, - const XML_Char *uri); - -typedef void (XMLCALL *XML_EndNamespaceDeclHandler) ( - void *userData, - const XML_Char *prefix); - -/* This is called if the document is not standalone, that is, it has an - external subset or a reference to a parameter entity, but does not - have standalone="yes". If this handler returns XML_STATUS_ERROR, - then processing will not continue, and the parser will return a - XML_ERROR_NOT_STANDALONE error. - If parameter entity parsing is enabled, then in addition to the - conditions above this handler will only be called if the referenced - entity was actually read. -*/ -typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData); - -/* This is called for a reference to an external parsed general - entity. The referenced entity is not automatically parsed. The - application can parse it immediately or later using - XML_ExternalEntityParserCreate. - - The parser argument is the parser parsing the entity containing the - reference; it can be passed as the parser argument to - XML_ExternalEntityParserCreate. The systemId argument is the - system identifier as specified in the entity declaration; it will - not be NULL. - - The base argument is the system identifier that should be used as - the base for resolving systemId if systemId was relative; this is - set by XML_SetBase; it may be NULL. - - The publicId argument is the public identifier as specified in the - entity declaration, or NULL if none was specified; the whitespace - in the public identifier will have been normalized as required by - the XML spec. - - The context argument specifies the parsing context in the format - expected by the context argument to XML_ExternalEntityParserCreate; - context is valid only until the handler returns, so if the - referenced entity is to be parsed later, it must be copied. - context is NULL only when the entity is a parameter entity. - - The handler should return XML_STATUS_ERROR if processing should not - continue because of a fatal error in the handling of the external - entity. In this case the calling parser will return an - XML_ERROR_EXTERNAL_ENTITY_HANDLING error. - - Note that unlike other handlers the first argument is the parser, - not userData. -*/ -typedef int (XMLCALL *XML_ExternalEntityRefHandler) ( - XML_Parser parser, - const XML_Char *context, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId); - -/* This is called in two situations: - 1) An entity reference is encountered for which no declaration - has been read *and* this is not an error. - 2) An internal entity reference is read, but not expanded, because - XML_SetDefaultHandler has been called. - Note: skipped parameter entities in declarations and skipped general - entities in attribute values cannot be reported, because - the event would be out of sync with the reporting of the - declarations or attribute values -*/ -typedef void (XMLCALL *XML_SkippedEntityHandler) ( - void *userData, - const XML_Char *entityName, - int is_parameter_entity); - -/* This structure is filled in by the XML_UnknownEncodingHandler to - provide information to the parser about encodings that are unknown - to the parser. - - The map[b] member gives information about byte sequences whose - first byte is b. - - If map[b] is c where c is >= 0, then b by itself encodes the - Unicode scalar value c. - - If map[b] is -1, then the byte sequence is malformed. - - If map[b] is -n, where n >= 2, then b is the first byte of an - n-byte sequence that encodes a single Unicode scalar value. - - The data member will be passed as the first argument to the convert - function. - - The convert function is used to convert multibyte sequences; s will - point to a n-byte sequence where map[(unsigned char)*s] == -n. The - convert function must return the Unicode scalar value represented - by this byte sequence or -1 if the byte sequence is malformed. - - The convert function may be NULL if the encoding is a single-byte - encoding, that is if map[b] >= -1 for all bytes b. - - When the parser is finished with the encoding, then if release is - not NULL, it will call release passing it the data member; once - release has been called, the convert function will not be called - again. - - Expat places certain restrictions on the encodings that are supported - using this mechanism. - - 1. Every ASCII character that can appear in a well-formed XML document, - other than the characters - - $@\^`{}~ - - must be represented by a single byte, and that byte must be the - same byte that represents that character in ASCII. - - 2. No character may require more than 4 bytes to encode. - - 3. All characters encoded must have Unicode scalar values <= - 0xFFFF, (i.e., characters that would be encoded by surrogates in - UTF-16 are not allowed). Note that this restriction doesn't - apply to the built-in support for UTF-8 and UTF-16. - - 4. No Unicode character may be encoded by more than one distinct - sequence of bytes. -*/ -typedef struct { - int map[256]; - void *data; - int (XMLCALL *convert)(void *data, const char *s); - void (XMLCALL *release)(void *data); -} XML_Encoding; - -/* This is called for an encoding that is unknown to the parser. - - The encodingHandlerData argument is that which was passed as the - second argument to XML_SetUnknownEncodingHandler. - - The name argument gives the name of the encoding as specified in - the encoding declaration. - - If the callback can provide information about the encoding, it must - fill in the XML_Encoding structure, and return XML_STATUS_OK. - Otherwise it must return XML_STATUS_ERROR. - - If info does not describe a suitable encoding, then the parser will - return an XML_UNKNOWN_ENCODING error. -*/ -typedef int (XMLCALL *XML_UnknownEncodingHandler) ( - void *encodingHandlerData, - const XML_Char *name, - XML_Encoding *info); - -XMLPARSEAPI(void) -XML_SetElementHandler(XML_Parser parser, - XML_StartElementHandler start, - XML_EndElementHandler end); - -XMLPARSEAPI(void) -XML_SetStartElementHandler(XML_Parser parser, - XML_StartElementHandler handler); - -XMLPARSEAPI(void) -XML_SetEndElementHandler(XML_Parser parser, - XML_EndElementHandler handler); - -XMLPARSEAPI(void) -XML_SetCharacterDataHandler(XML_Parser parser, - XML_CharacterDataHandler handler); - -XMLPARSEAPI(void) -XML_SetProcessingInstructionHandler(XML_Parser parser, - XML_ProcessingInstructionHandler handler); -XMLPARSEAPI(void) -XML_SetCommentHandler(XML_Parser parser, - XML_CommentHandler handler); - -XMLPARSEAPI(void) -XML_SetCdataSectionHandler(XML_Parser parser, - XML_StartCdataSectionHandler start, - XML_EndCdataSectionHandler end); - -XMLPARSEAPI(void) -XML_SetStartCdataSectionHandler(XML_Parser parser, - XML_StartCdataSectionHandler start); - -XMLPARSEAPI(void) -XML_SetEndCdataSectionHandler(XML_Parser parser, - XML_EndCdataSectionHandler end); - -/* This sets the default handler and also inhibits expansion of - internal entities. These entity references will be passed to the - default handler, or to the skipped entity handler, if one is set. -*/ -XMLPARSEAPI(void) -XML_SetDefaultHandler(XML_Parser parser, - XML_DefaultHandler handler); - -/* This sets the default handler but does not inhibit expansion of - internal entities. The entity reference will not be passed to the - default handler. -*/ -XMLPARSEAPI(void) -XML_SetDefaultHandlerExpand(XML_Parser parser, - XML_DefaultHandler handler); - -XMLPARSEAPI(void) -XML_SetDoctypeDeclHandler(XML_Parser parser, - XML_StartDoctypeDeclHandler start, - XML_EndDoctypeDeclHandler end); - -XMLPARSEAPI(void) -XML_SetStartDoctypeDeclHandler(XML_Parser parser, - XML_StartDoctypeDeclHandler start); - -XMLPARSEAPI(void) -XML_SetEndDoctypeDeclHandler(XML_Parser parser, - XML_EndDoctypeDeclHandler end); - -XMLPARSEAPI(void) -XML_SetUnparsedEntityDeclHandler(XML_Parser parser, - XML_UnparsedEntityDeclHandler handler); - -XMLPARSEAPI(void) -XML_SetNotationDeclHandler(XML_Parser parser, - XML_NotationDeclHandler handler); - -XMLPARSEAPI(void) -XML_SetNamespaceDeclHandler(XML_Parser parser, - XML_StartNamespaceDeclHandler start, - XML_EndNamespaceDeclHandler end); - -XMLPARSEAPI(void) -XML_SetStartNamespaceDeclHandler(XML_Parser parser, - XML_StartNamespaceDeclHandler start); - -XMLPARSEAPI(void) -XML_SetEndNamespaceDeclHandler(XML_Parser parser, - XML_EndNamespaceDeclHandler end); - -XMLPARSEAPI(void) -XML_SetNotStandaloneHandler(XML_Parser parser, - XML_NotStandaloneHandler handler); - -XMLPARSEAPI(void) -XML_SetExternalEntityRefHandler(XML_Parser parser, - XML_ExternalEntityRefHandler handler); - -/* If a non-NULL value for arg is specified here, then it will be - passed as the first argument to the external entity ref handler - instead of the parser object. -*/ -XMLPARSEAPI(void) -XML_SetExternalEntityRefHandlerArg(XML_Parser parser, - void *arg); - -XMLPARSEAPI(void) -XML_SetSkippedEntityHandler(XML_Parser parser, - XML_SkippedEntityHandler handler); - -XMLPARSEAPI(void) -XML_SetUnknownEncodingHandler(XML_Parser parser, - XML_UnknownEncodingHandler handler, - void *encodingHandlerData); - -/* This can be called within a handler for a start element, end - element, processing instruction or character data. It causes the - corresponding markup to be passed to the default handler. -*/ -XMLPARSEAPI(void) -XML_DefaultCurrent(XML_Parser parser); - -/* If do_nst is non-zero, and namespace processing is in effect, and - a name has a prefix (i.e. an explicit namespace qualifier) then - that name is returned as a triplet in a single string separated by - the separator character specified when the parser was created: URI - + sep + local_name + sep + prefix. - - If do_nst is zero, then namespace information is returned in the - default manner (URI + sep + local_name) whether or not the name - has a prefix. - - Note: Calling XML_SetReturnNSTriplet after XML_Parse or - XML_ParseBuffer has no effect. -*/ - -XMLPARSEAPI(void) -XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); - -/* This value is passed as the userData argument to callbacks. */ -XMLPARSEAPI(void) -XML_SetUserData(XML_Parser parser, void *userData); - -/* Returns the last value set by XML_SetUserData or NULL. */ -#define XML_GetUserData(parser) (*(void **)(parser)) - -/* This is equivalent to supplying an encoding argument to - XML_ParserCreate. On success XML_SetEncoding returns non-zero, - zero otherwise. - Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer - has no effect and returns XML_STATUS_ERROR. -*/ -XMLPARSEAPI(enum XML_Status) -XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); - -/* If this function is called, then the parser will be passed as the - first argument to callbacks instead of userData. The userData will - still be accessible using XML_GetUserData. -*/ -XMLPARSEAPI(void) -XML_UseParserAsHandlerArg(XML_Parser parser); - -/* If useDTD == XML_TRUE is passed to this function, then the parser - will assume that there is an external subset, even if none is - specified in the document. In such a case the parser will call the - externalEntityRefHandler with a value of NULL for the systemId - argument (the publicId and context arguments will be NULL as well). - Note: For the purpose of checking WFC: Entity Declared, passing - useDTD == XML_TRUE will make the parser behave as if the document - had a DTD with an external subset. - Note: If this function is called, then this must be done before - the first call to XML_Parse or XML_ParseBuffer, since it will - have no effect after that. Returns - XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING. - Note: If the document does not have a DOCTYPE declaration at all, - then startDoctypeDeclHandler and endDoctypeDeclHandler will not - be called, despite an external subset being parsed. - Note: If XML_DTD is not defined when Expat is compiled, returns - XML_ERROR_FEATURE_REQUIRES_XML_DTD. -*/ -XMLPARSEAPI(enum XML_Error) -XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD); - - -/* Sets the base to be used for resolving relative URIs in system - identifiers in declarations. Resolving relative identifiers is - left to the application: this value will be passed through as the - base argument to the XML_ExternalEntityRefHandler, - XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base - argument will be copied. Returns XML_STATUS_ERROR if out of memory, - XML_STATUS_OK otherwise. -*/ -XMLPARSEAPI(enum XML_Status) -XML_SetBase(XML_Parser parser, const XML_Char *base); - -XMLPARSEAPI(const XML_Char *) -XML_GetBase(XML_Parser parser); - -/* Returns the number of the attribute/value pairs passed in last call - to the XML_StartElementHandler that were specified in the start-tag - rather than defaulted. Each attribute/value pair counts as 2; thus - this correspondds to an index into the atts array passed to the - XML_StartElementHandler. -*/ -XMLPARSEAPI(int) -XML_GetSpecifiedAttributeCount(XML_Parser parser); - -/* Returns the index of the ID attribute passed in the last call to - XML_StartElementHandler, or -1 if there is no ID attribute. Each - attribute/value pair counts as 2; thus this correspondds to an - index into the atts array passed to the XML_StartElementHandler. -*/ -XMLPARSEAPI(int) -XML_GetIdAttributeIndex(XML_Parser parser); - -#ifdef XML_ATTR_INFO -/* Source file byte offsets for the start and end of attribute names and values. - The value indices are exclusive of surrounding quotes; thus in a UTF-8 source - file an attribute value of "blah" will yield: - info->valueEnd - info->valueStart = 4 bytes. -*/ -typedef struct { - XML_Index nameStart; /* Offset to beginning of the attribute name. */ - XML_Index nameEnd; /* Offset after the attribute name's last byte. */ - XML_Index valueStart; /* Offset to beginning of the attribute value. */ - XML_Index valueEnd; /* Offset after the attribute value's last byte. */ -} XML_AttrInfo; - -/* Returns an array of XML_AttrInfo structures for the attribute/value pairs - passed in last call to the XML_StartElementHandler that were specified - in the start-tag rather than defaulted. Each attribute/value pair counts - as 1; thus the number of entries in the array is - XML_GetSpecifiedAttributeCount(parser) / 2. -*/ -XMLPARSEAPI(const XML_AttrInfo *) -XML_GetAttributeInfo(XML_Parser parser); -#endif - -/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is - detected. The last call to XML_Parse must have isFinal true; len - may be zero for this call (or any other). - - Though the return values for these functions has always been - described as a Boolean value, the implementation, at least for the - 1.95.x series, has always returned exactly one of the XML_Status - values. -*/ -XMLPARSEAPI(enum XML_Status) -XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); - -XMLPARSEAPI(void *) -XML_GetBuffer(XML_Parser parser, int len); - -XMLPARSEAPI(enum XML_Status) -XML_ParseBuffer(XML_Parser parser, int len, int isFinal); - -/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return. - Must be called from within a call-back handler, except when aborting - (resumable = 0) an already suspended parser. Some call-backs may - still follow because they would otherwise get lost. Examples: - - endElementHandler() for empty elements when stopped in - startElementHandler(), - - endNameSpaceDeclHandler() when stopped in endElementHandler(), - and possibly others. - - Can be called from most handlers, including DTD related call-backs, - except when parsing an external parameter entity and resumable != 0. - Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise. - Possible error codes: - - XML_ERROR_SUSPENDED: when suspending an already suspended parser. - - XML_ERROR_FINISHED: when the parser has already finished. - - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE. - - When resumable != 0 (true) then parsing is suspended, that is, - XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED. - Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer() - return XML_STATUS_ERROR with error code XML_ERROR_ABORTED. - - *Note*: - This will be applied to the current parser instance only, that is, if - there is a parent parser then it will continue parsing when the - externalEntityRefHandler() returns. It is up to the implementation of - the externalEntityRefHandler() to call XML_StopParser() on the parent - parser (recursively), if one wants to stop parsing altogether. - - When suspended, parsing can be resumed by calling XML_ResumeParser(). -*/ -XMLPARSEAPI(enum XML_Status) -XML_StopParser(XML_Parser parser, XML_Bool resumable); - -/* Resumes parsing after it has been suspended with XML_StopParser(). - Must not be called from within a handler call-back. Returns same - status codes as XML_Parse() or XML_ParseBuffer(). - Additional error code XML_ERROR_NOT_SUSPENDED possible. - - *Note*: - This must be called on the most deeply nested child parser instance - first, and on its parent parser only after the child parser has finished, - to be applied recursively until the document entity's parser is restarted. - That is, the parent parser will not resume by itself and it is up to the - application to call XML_ResumeParser() on it at the appropriate moment. -*/ -XMLPARSEAPI(enum XML_Status) -XML_ResumeParser(XML_Parser parser); - -enum XML_Parsing { - XML_INITIALIZED, - XML_PARSING, - XML_FINISHED, - XML_SUSPENDED -}; - -typedef struct { - enum XML_Parsing parsing; - XML_Bool finalBuffer; -} XML_ParsingStatus; - -/* Returns status of parser with respect to being initialized, parsing, - finished, or suspended and processing the final buffer. - XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus, - XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED -*/ -XMLPARSEAPI(void) -XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status); - -/* Creates an XML_Parser object that can parse an external general - entity; context is a '\0'-terminated string specifying the parse - context; encoding is a '\0'-terminated string giving the name of - the externally specified encoding, or NULL if there is no - externally specified encoding. The context string consists of a - sequence of tokens separated by formfeeds (\f); a token consisting - of a name specifies that the general entity of the name is open; a - token of the form prefix=uri specifies the namespace for a - particular prefix; a token of the form =uri specifies the default - namespace. This can be called at any point after the first call to - an ExternalEntityRefHandler so longer as the parser has not yet - been freed. The new parser is completely independent and may - safely be used in a separate thread. The handlers and userData are - initialized from the parser argument. Returns NULL if out of memory. - Otherwise returns a new XML_Parser object. -*/ -XMLPARSEAPI(XML_Parser) -XML_ExternalEntityParserCreate(XML_Parser parser, - const XML_Char *context, - const XML_Char *encoding); - -enum XML_ParamEntityParsing { - XML_PARAM_ENTITY_PARSING_NEVER, - XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, - XML_PARAM_ENTITY_PARSING_ALWAYS -}; - -/* Controls parsing of parameter entities (including the external DTD - subset). If parsing of parameter entities is enabled, then - references to external parameter entities (including the external - DTD subset) will be passed to the handler set with - XML_SetExternalEntityRefHandler. The context passed will be 0. - - Unlike external general entities, external parameter entities can - only be parsed synchronously. If the external parameter entity is - to be parsed, it must be parsed during the call to the external - entity ref handler: the complete sequence of - XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and - XML_ParserFree calls must be made during this call. After - XML_ExternalEntityParserCreate has been called to create the parser - for the external parameter entity (context must be 0 for this - call), it is illegal to make any calls on the old parser until - XML_ParserFree has been called on the newly created parser. - If the library has been compiled without support for parameter - entity parsing (ie without XML_DTD being defined), then - XML_SetParamEntityParsing will return 0 if parsing of parameter - entities is requested; otherwise it will return non-zero. - Note: If XML_SetParamEntityParsing is called after XML_Parse or - XML_ParseBuffer, then it has no effect and will always return 0. -*/ -XMLPARSEAPI(int) -XML_SetParamEntityParsing(XML_Parser parser, - enum XML_ParamEntityParsing parsing); - -/* Sets the hash salt to use for internal hash calculations. - Helps in preventing DoS attacks based on predicting hash - function behavior. This must be called before parsing is started. - Returns 1 if successful, 0 when called after parsing has started. -*/ -XMLPARSEAPI(int) -XML_SetHashSalt(XML_Parser parser, - unsigned long hash_salt); - -/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then - XML_GetErrorCode returns information about the error. -*/ -XMLPARSEAPI(enum XML_Error) -XML_GetErrorCode(XML_Parser parser); - -/* These functions return information about the current parse - location. They may be called from any callback called to report - some parse event; in this case the location is the location of the - first of the sequence of characters that generated the event. When - called from callbacks generated by declarations in the document - prologue, the location identified isn't as neatly defined, but will - be within the relevant markup. When called outside of the callback - functions, the position indicated will be just past the last parse - event (regardless of whether there was an associated callback). - - They may also be called after returning from a call to XML_Parse - or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then - the location is the location of the character at which the error - was detected; otherwise the location is the location of the last - parse event, as described above. -*/ -XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser); -XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser); -XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser); - -/* Return the number of bytes in the current event. - Returns 0 if the event is in an internal entity. -*/ -XMLPARSEAPI(int) -XML_GetCurrentByteCount(XML_Parser parser); - -/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets - the integer pointed to by offset to the offset within this buffer - of the current parse position, and sets the integer pointed to by size - to the size of this buffer (the number of input bytes). Otherwise - returns a NULL pointer. Also returns a NULL pointer if a parse isn't - active. - - NOTE: The character pointer returned should not be used outside - the handler that makes the call. -*/ -XMLPARSEAPI(const char *) -XML_GetInputContext(XML_Parser parser, - int *offset, - int *size); - -/* For backwards compatibility with previous versions. */ -#define XML_GetErrorLineNumber XML_GetCurrentLineNumber -#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber -#define XML_GetErrorByteIndex XML_GetCurrentByteIndex - -/* Frees the content model passed to the element declaration handler */ -XMLPARSEAPI(void) -XML_FreeContentModel(XML_Parser parser, XML_Content *model); - -/* Exposing the memory handling functions used in Expat */ -XMLPARSEAPI(void *) -XML_MemMalloc(XML_Parser parser, size_t size); - -XMLPARSEAPI(void *) -XML_MemRealloc(XML_Parser parser, void *ptr, size_t size); - -XMLPARSEAPI(void) -XML_MemFree(XML_Parser parser, void *ptr); - -/* Frees memory used by the parser. */ -XMLPARSEAPI(void) -XML_ParserFree(XML_Parser parser); - -/* Returns a string describing the error. */ -XMLPARSEAPI(const XML_LChar *) -XML_ErrorString(enum XML_Error code); - -/* Return a string containing the version number of this expat */ -XMLPARSEAPI(const XML_LChar *) -XML_ExpatVersion(void); - -typedef struct { - int major; - int minor; - int micro; -} XML_Expat_Version; - -/* Return an XML_Expat_Version structure containing numeric version - number information for this version of expat. -*/ -XMLPARSEAPI(XML_Expat_Version) -XML_ExpatVersionInfo(void); - -/* Added in Expat 1.95.5. */ -enum XML_FeatureEnum { - XML_FEATURE_END = 0, - XML_FEATURE_UNICODE, - XML_FEATURE_UNICODE_WCHAR_T, - XML_FEATURE_DTD, - XML_FEATURE_CONTEXT_BYTES, - XML_FEATURE_MIN_SIZE, - XML_FEATURE_SIZEOF_XML_CHAR, - XML_FEATURE_SIZEOF_XML_LCHAR, - XML_FEATURE_NS, - XML_FEATURE_LARGE_SIZE, - XML_FEATURE_ATTR_INFO - /* Additional features must be added to the end of this enum. */ -}; - -typedef struct { - enum XML_FeatureEnum feature; - const XML_LChar *name; - long int value; -} XML_Feature; - -XMLPARSEAPI(const XML_Feature *) -XML_GetFeatureList(void); - - -/* Expat follows the GNU/Linux convention of odd number minor version for - beta/development releases and even number minor version for stable - releases. Micro is bumped with each release, and set to 0 with each - change to major or minor version. -*/ -#define XML_MAJOR_VERSION 2 -#define XML_MINOR_VERSION 1 -#define XML_MICRO_VERSION 0 - -#ifdef __cplusplus -} -#endif - -#endif /* not Expat_INCLUDED */ diff -Nru simgear-2.10.0/simgear/xml/hashtable.c simgear-3.0.0/simgear/xml/hashtable.c --- simgear-2.10.0/simgear/xml/hashtable.c 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/xml/hashtable.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,151 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (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.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -#include "xmldef.h" - -#ifdef XML_UNICODE_WCHAR_T -#ifndef XML_UNICODE -#define XML_UNICODE -#endif -#endif - -#include "hashtable.h" - -#define INIT_SIZE 64 - -static -int keyeq(KEY s1, KEY s2) -{ - for (; *s1 == *s2; s1++, s2++) - if (*s1 == 0) - return 1; - return 0; -} - -static -unsigned long hash(KEY s) -{ - unsigned long h = 0; - while (*s) - h = (h << 5) + h + (unsigned char)*s++; - return h; -} - -NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize) -{ - size_t i; - if (table->size == 0) { - if (!createSize) - return 0; - table->v = calloc(INIT_SIZE, sizeof(NAMED *)); - if (!table->v) - return 0; - table->size = INIT_SIZE; - table->usedLim = INIT_SIZE / 2; - i = hash(name) & (table->size - 1); - } - else { - unsigned long h = hash(name); - for (i = h & (table->size - 1); - table->v[i]; - i == 0 ? i = table->size - 1 : --i) { - if (keyeq(name, table->v[i]->name)) - return table->v[i]; - } - if (!createSize) - return 0; - if (table->used == table->usedLim) { - /* check for overflow */ - size_t newSize = table->size * 2; - NAMED **newV = calloc(newSize, sizeof(NAMED *)); - if (!newV) - return 0; - for (i = 0; i < table->size; i++) - if (table->v[i]) { - size_t j; - for (j = hash(table->v[i]->name) & (newSize - 1); - newV[j]; - j == 0 ? j = newSize - 1 : --j) - ; - newV[j] = table->v[i]; - } - free(table->v); - table->v = newV; - table->size = newSize; - table->usedLim = newSize/2; - for (i = h & (table->size - 1); - table->v[i]; - i == 0 ? i = table->size - 1 : --i) - ; - } - } - table->v[i] = calloc(1, createSize); - if (!table->v[i]) - return 0; - table->v[i]->name = name; - (table->used)++; - return table->v[i]; -} - -void hashTableDestroy(HASH_TABLE *table) -{ - size_t i; - for (i = 0; i < table->size; i++) { - NAMED *p = table->v[i]; - if (p) - free(p); - } - free(table->v); -} - -void hashTableInit(HASH_TABLE *p) -{ - p->size = 0; - p->usedLim = 0; - p->used = 0; - p->v = 0; -} - -void hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) -{ - iter->p = table->v; - iter->end = iter->p + table->size; -} - -NAMED *hashTableIterNext(HASH_TABLE_ITER *iter) -{ - while (iter->p != iter->end) { - NAMED *tem = *(iter->p)++; - if (tem) - return tem; - } - return 0; -} - diff -Nru simgear-2.10.0/simgear/xml/hashtable.h simgear-3.0.0/simgear/xml/hashtable.h --- simgear-2.10.0/simgear/xml/hashtable.h 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/xml/hashtable.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,69 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (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.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - - -#include - -#ifdef XML_UNICODE - -#ifdef XML_UNICODE_WCHAR_T -typedef const wchar_t *KEY; -#else /* not XML_UNICODE_WCHAR_T */ -typedef const unsigned short *KEY; -#endif /* not XML_UNICODE_WCHAR_T */ - -#else /* not XML_UNICODE */ - -typedef const char *KEY; - -#endif /* not XML_UNICODE */ - -typedef struct { - KEY name; -} NAMED; - -typedef struct { - NAMED **v; - size_t size; - size_t used; - size_t usedLim; -} HASH_TABLE; - -NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize); -void hashTableInit(HASH_TABLE *); -void hashTableDestroy(HASH_TABLE *); - -typedef struct { - NAMED **p; - NAMED **end; -} HASH_TABLE_ITER; - -void hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); -NAMED *hashTableIterNext(HASH_TABLE_ITER *); diff -Nru simgear-2.10.0/simgear/xml/iasciitab.h simgear-3.0.0/simgear/xml/iasciitab.h --- simgear-2.10.0/simgear/xml/iasciitab.h 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/xml/iasciitab.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (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.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */ -/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, -/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML, -/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, -/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, -/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, -/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, -/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, -/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, -/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, -/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, -/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, -/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, -/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, -/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, -/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, -/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, -/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, -/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff -Nru simgear-2.10.0/simgear/xml/internal.h simgear-3.0.0/simgear/xml/internal.h --- simgear-2.10.0/simgear/xml/internal.h 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/internal.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,73 +0,0 @@ -/* internal.h - - Internal definitions used by Expat. This is not needed to compile - client code. - - The following calling convention macros are defined for frequently - called functions: - - FASTCALL - Used for those internal functions that have a simple - body and a low number of arguments and local variables. - - PTRCALL - Used for functions called though function pointers. - - PTRFASTCALL - Like PTRCALL, but for low number of arguments. - - inline - Used for selected internal functions for which inlining - may improve performance on some platforms. - - Note: Use of these macros is based on judgement, not hard rules, - and therefore subject to change. -*/ - -#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__) -/* We'll use this version by default only where we know it helps. - - regparm() generates warnings on Solaris boxes. See SF bug #692878. - - Instability reported with egcs on a RedHat Linux 7.3. - Let's comment out: - #define FASTCALL __attribute__((stdcall, regparm(3))) - and let's try this: -*/ -#define FASTCALL __attribute__((regparm(3))) -#define PTRFASTCALL __attribute__((regparm(3))) -#endif - -/* Using __fastcall seems to have an unexpected negative effect under - MS VC++, especially for function pointers, so we won't use it for - now on that platform. It may be reconsidered for a future release - if it can be made more effective. - Likely reason: __fastcall on Windows is like stdcall, therefore - the compiler cannot perform stack optimizations for call clusters. -*/ - -/* Make sure all of these are defined if they aren't already. */ - -#ifndef FASTCALL -#define FASTCALL -#endif - -#ifndef PTRCALL -#define PTRCALL -#endif - -#ifndef PTRFASTCALL -#define PTRFASTCALL -#endif - -#ifndef XML_MIN_SIZE -#if !defined(__cplusplus) && !defined(inline) -#ifdef __GNUC__ -#define inline __inline -#endif /* __GNUC__ */ -#endif -#endif /* XML_MIN_SIZE */ - -#ifdef __cplusplus -#define inline inline -#else -#ifndef inline -#define inline -#endif -#endif diff -Nru simgear-2.10.0/simgear/xml/latin1tab.h simgear-3.0.0/simgear/xml/latin1tab.h --- simgear-2.10.0/simgear/xml/latin1tab.h 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/xml/latin1tab.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (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.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, -/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME, -/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, -/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, -/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, -/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, -/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, -/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, diff -Nru simgear-2.10.0/simgear/xml/nametab.h simgear-3.0.0/simgear/xml/nametab.h --- simgear-2.10.0/simgear/xml/nametab.h 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/xml/nametab.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,150 +0,0 @@ -static const unsigned namingBitmap[] = { -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE, -0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF, -0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF, -0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, -0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, -0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, -0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, -0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, -0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, -0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000, -0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060, -0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, -0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003, -0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000, -0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, -0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003, -0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000, -0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, -0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003, -0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000, -0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000, -0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, -0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB, -0x40000000, 0xF580C900, 0x00000007, 0x02010800, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF, -0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF, -0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, -0x00000000, 0x00004C40, 0x00000000, 0x00000000, -0x00000007, 0x00000000, 0x00000000, 0x00000000, -0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, -0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF, -0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000, -0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE, -0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, -0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, -0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000, -0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, -0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, -0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, -0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, -0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, -0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF, -0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, -0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF, -0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF, -0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, -0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0, -0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1, -0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, -0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80, -0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3, -0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, -0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, -0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000, -0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF, -0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x00000000, 0x00000000, -0x00000000, 0x00000000, 0x1FFF0000, 0x00000002, -0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, -0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF, -}; -static const unsigned char nmstrtPages[] = { -0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, -0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, -0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, -0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; -static const unsigned char namePages[] = { -0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, -0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, -0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, -0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; diff -Nru simgear-2.10.0/simgear/xml/utf8tab.h simgear-3.0.0/simgear/xml/utf8tab.h --- simgear-2.10.0/simgear/xml/utf8tab.h 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/xml/utf8tab.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (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.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - - -/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, -/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, -/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, -/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, -/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, -/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, -/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4, -/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, -/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM, diff -Nru simgear-2.10.0/simgear/xml/xmldef.h simgear-3.0.0/simgear/xml/xmldef.h --- simgear-2.10.0/simgear/xml/xmldef.h 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/xml/xmldef.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (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.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -#include - -#ifdef XML_WINLIB - -#define WIN32_LEAN_AND_MEAN -#define STRICT -#include - -#define malloc(x) HeapAlloc(GetProcessHeap(), 0, (x)) -#define calloc(x, y) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (x)*(y)) -#define free(x) HeapFree(GetProcessHeap(), 0, (x)) -#define realloc(x, y) HeapReAlloc(GetProcessHeap(), 0, x, y) -#define abort() /* as nothing */ - -#else /* not XML_WINLIB */ - -#include - -#endif /* not XML_WINLIB */ - -/* This file can be used for any definitions needed in -particular environments. */ - -#ifdef MOZILLA - -#include -#define malloc(x) PR_Malloc(x) -#define realloc(x, y) PR_Realloc((x), (y)) -#define calloc(x, y) PR_Calloc((x),(y)) -#define free(x) PR_Free(x) -#define int int32 - -#endif /* MOZILLA */ diff -Nru simgear-2.10.0/simgear/xml/xmlparse.c simgear-3.0.0/simgear/xml/xmlparse.c --- simgear-2.10.0/simgear/xml/xmlparse.c 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/xmlparse.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,6403 +0,0 @@ -/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd - See the file COPYING for copying permission. -*/ - -#include -#include /* memset(), memcpy() */ -#include -#include /* UINT_MAX */ -#include /* time() */ - -#define XML_BUILDING_EXPAT 1 - -#ifdef COMPILED_FROM_DSP -#include "winconfig.h" -#elif defined(MACOS_CLASSIC) -#include "macconfig.h" -#elif defined(__amigaos__) -#include "amigaconfig.h" -#elif defined(__WATCOMC__) -#include "watcomconfig.h" -#elif defined(HAVE_EXPAT_CONFIG_H) -#include "expat_config.h" -#endif /* ndef COMPILED_FROM_DSP */ - -#include "ascii.h" -#include "expat.h" - -#ifdef XML_UNICODE -#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX -#define XmlConvert XmlUtf16Convert -#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding -#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS -#define XmlEncode XmlUtf16Encode -/* Using pointer subtraction to convert to integer type. */ -#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1)) -typedef unsigned short ICHAR; -#else -#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX -#define XmlConvert XmlUtf8Convert -#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding -#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS -#define XmlEncode XmlUtf8Encode -#define MUST_CONVERT(enc, s) (!(enc)->isUtf8) -typedef char ICHAR; -#endif - - -#ifndef XML_NS - -#define XmlInitEncodingNS XmlInitEncoding -#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding -#undef XmlGetInternalEncodingNS -#define XmlGetInternalEncodingNS XmlGetInternalEncoding -#define XmlParseXmlDeclNS XmlParseXmlDecl - -#endif - -#ifdef XML_UNICODE - -#ifdef XML_UNICODE_WCHAR_T -#define XML_T(x) (const wchar_t)x -#define XML_L(x) L ## x -#else -#define XML_T(x) (const unsigned short)x -#define XML_L(x) x -#endif - -#else - -#define XML_T(x) x -#define XML_L(x) x - -#endif - -/* Round up n to be a multiple of sz, where sz is a power of 2. */ -#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) - -/* Handle the case where memmove() doesn't exist. */ -#ifndef HAVE_MEMMOVE -#ifdef HAVE_BCOPY -#define memmove(d,s,l) bcopy((s),(d),(l)) -#else -#error memmove does not exist on this platform, nor is a substitute available -#endif /* HAVE_BCOPY */ -#endif /* HAVE_MEMMOVE */ - -#include "internal.h" -#include "xmltok.h" -#include "xmlrole.h" - -typedef const XML_Char *KEY; - -typedef struct { - KEY name; -} NAMED; - -typedef struct { - NAMED **v; - unsigned char power; - size_t size; - size_t used; - const XML_Memory_Handling_Suite *mem; -} HASH_TABLE; - -/* Basic character hash algorithm, taken from Python's string hash: - h = h * 1000003 ^ character, the constant being a prime number. - -*/ -#ifdef XML_UNICODE -#define CHAR_HASH(h, c) \ - (((h) * 0xF4243) ^ (unsigned short)(c)) -#else -#define CHAR_HASH(h, c) \ - (((h) * 0xF4243) ^ (unsigned char)(c)) -#endif - -/* For probing (after a collision) we need a step size relative prime - to the hash table size, which is a power of 2. We use double-hashing, - since we can calculate a second hash value cheaply by taking those bits - of the first hash value that were discarded (masked out) when the table - index was calculated: index = hash & mask, where mask = table->size - 1. - We limit the maximum step size to table->size / 4 (mask >> 2) and make - it odd, since odd numbers are always relative prime to a power of 2. -*/ -#define SECOND_HASH(hash, mask, power) \ - ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2)) -#define PROBE_STEP(hash, mask, power) \ - ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1)) - -typedef struct { - NAMED **p; - NAMED **end; -} HASH_TABLE_ITER; - -#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */ -#define INIT_DATA_BUF_SIZE 1024 -#define INIT_ATTS_SIZE 16 -#define INIT_ATTS_VERSION 0xFFFFFFFF -#define INIT_BLOCK_SIZE 1024 -#define INIT_BUFFER_SIZE 1024 - -#define EXPAND_SPARE 24 - -typedef struct binding { - struct prefix *prefix; - struct binding *nextTagBinding; - struct binding *prevPrefixBinding; - const struct attribute_id *attId; - XML_Char *uri; - int uriLen; - int uriAlloc; -} BINDING; - -typedef struct prefix { - const XML_Char *name; - BINDING *binding; -} PREFIX; - -typedef struct { - const XML_Char *str; - const XML_Char *localPart; - const XML_Char *prefix; - int strLen; - int uriLen; - int prefixLen; -} TAG_NAME; - -/* TAG represents an open element. - The name of the element is stored in both the document and API - encodings. The memory buffer 'buf' is a separately-allocated - memory area which stores the name. During the XML_Parse()/ - XMLParseBuffer() when the element is open, the memory for the 'raw' - version of the name (in the document encoding) is shared with the - document buffer. If the element is open across calls to - XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to - contain the 'raw' name as well. - - A parser re-uses these structures, maintaining a list of allocated - TAG objects in a free list. -*/ -typedef struct tag { - struct tag *parent; /* parent of this element */ - const char *rawName; /* tagName in the original encoding */ - int rawNameLength; - TAG_NAME name; /* tagName in the API encoding */ - char *buf; /* buffer for name components */ - char *bufEnd; /* end of the buffer */ - BINDING *bindings; -} TAG; - -typedef struct { - const XML_Char *name; - const XML_Char *textPtr; - int textLen; /* length in XML_Chars */ - int processed; /* # of processed bytes - when suspended */ - const XML_Char *systemId; - const XML_Char *base; - const XML_Char *publicId; - const XML_Char *notation; - XML_Bool open; - XML_Bool is_param; - XML_Bool is_internal; /* true if declared in internal subset outside PE */ -} ENTITY; - -typedef struct { - enum XML_Content_Type type; - enum XML_Content_Quant quant; - const XML_Char * name; - int firstchild; - int lastchild; - int childcnt; - int nextsib; -} CONTENT_SCAFFOLD; - -#define INIT_SCAFFOLD_ELEMENTS 32 - -typedef struct block { - struct block *next; - int size; - XML_Char s[1]; -} BLOCK; - -typedef struct { - BLOCK *blocks; - BLOCK *freeBlocks; - const XML_Char *end; - XML_Char *ptr; - XML_Char *start; - const XML_Memory_Handling_Suite *mem; -} STRING_POOL; - -/* The XML_Char before the name is used to determine whether - an attribute has been specified. */ -typedef struct attribute_id { - XML_Char *name; - PREFIX *prefix; - XML_Bool maybeTokenized; - XML_Bool xmlns; -} ATTRIBUTE_ID; - -typedef struct { - const ATTRIBUTE_ID *id; - XML_Bool isCdata; - const XML_Char *value; -} DEFAULT_ATTRIBUTE; - -typedef struct { - unsigned long version; - unsigned long hash; - const XML_Char *uriName; -} NS_ATT; - -typedef struct { - const XML_Char *name; - PREFIX *prefix; - const ATTRIBUTE_ID *idAtt; - int nDefaultAtts; - int allocDefaultAtts; - DEFAULT_ATTRIBUTE *defaultAtts; -} ELEMENT_TYPE; - -typedef struct { - HASH_TABLE generalEntities; - HASH_TABLE elementTypes; - HASH_TABLE attributeIds; - HASH_TABLE prefixes; - STRING_POOL pool; - STRING_POOL entityValuePool; - /* false once a parameter entity reference has been skipped */ - XML_Bool keepProcessing; - /* true once an internal or external PE reference has been encountered; - this includes the reference to an external subset */ - XML_Bool hasParamEntityRefs; - XML_Bool standalone; -#ifdef XML_DTD - /* indicates if external PE has been read */ - XML_Bool paramEntityRead; - HASH_TABLE paramEntities; -#endif /* XML_DTD */ - PREFIX defaultPrefix; - /* === scaffolding for building content model === */ - XML_Bool in_eldecl; - CONTENT_SCAFFOLD *scaffold; - unsigned contentStringLen; - unsigned scaffSize; - unsigned scaffCount; - int scaffLevel; - int *scaffIndex; -} DTD; - -typedef struct open_internal_entity { - const char *internalEventPtr; - const char *internalEventEndPtr; - struct open_internal_entity *next; - ENTITY *entity; - int startTagLevel; - XML_Bool betweenDecl; /* WFC: PE Between Declarations */ -} OPEN_INTERNAL_ENTITY; - -typedef enum XML_Error PTRCALL Processor(XML_Parser parser, - const char *start, - const char *end, - const char **endPtr); - -static Processor prologProcessor; -static Processor prologInitProcessor; -static Processor contentProcessor; -static Processor cdataSectionProcessor; -#ifdef XML_DTD -static Processor ignoreSectionProcessor; -static Processor externalParEntProcessor; -static Processor externalParEntInitProcessor; -static Processor entityValueProcessor; -static Processor entityValueInitProcessor; -#endif /* XML_DTD */ -static Processor epilogProcessor; -static Processor errorProcessor; -static Processor externalEntityInitProcessor; -static Processor externalEntityInitProcessor2; -static Processor externalEntityInitProcessor3; -static Processor externalEntityContentProcessor; -static Processor internalEntityProcessor; - -static enum XML_Error -handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName); -static enum XML_Error -processXmlDecl(XML_Parser parser, int isGeneralTextEntity, - const char *s, const char *next); -static enum XML_Error -initializeEncoding(XML_Parser parser); -static enum XML_Error -doProlog(XML_Parser parser, const ENCODING *enc, const char *s, - const char *end, int tok, const char *next, const char **nextPtr, - XML_Bool haveMore); -static enum XML_Error -processInternalEntity(XML_Parser parser, ENTITY *entity, - XML_Bool betweenDecl); -static enum XML_Error -doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, - const char *start, const char *end, const char **endPtr, - XML_Bool haveMore); -static enum XML_Error -doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, - const char *end, const char **nextPtr, XML_Bool haveMore); -#ifdef XML_DTD -static enum XML_Error -doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr, - const char *end, const char **nextPtr, XML_Bool haveMore); -#endif /* XML_DTD */ - -static enum XML_Error -storeAtts(XML_Parser parser, const ENCODING *, const char *s, - TAG_NAME *tagNamePtr, BINDING **bindingsPtr); -static enum XML_Error -addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, - const XML_Char *uri, BINDING **bindingsPtr); -static int -defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata, - XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser); -static enum XML_Error -storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata, - const char *, const char *, STRING_POOL *); -static enum XML_Error -appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata, - const char *, const char *, STRING_POOL *); -static ATTRIBUTE_ID * -getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, - const char *end); -static int -setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *); -static enum XML_Error -storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start, - const char *end); -static int -reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, - const char *start, const char *end); -static int -reportComment(XML_Parser parser, const ENCODING *enc, const char *start, - const char *end); -static void -reportDefault(XML_Parser parser, const ENCODING *enc, const char *start, - const char *end); - -static const XML_Char * getContext(XML_Parser parser); -static XML_Bool -setContext(XML_Parser parser, const XML_Char *context); - -static void FASTCALL normalizePublicId(XML_Char *s); - -static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms); -/* do not call if parentParser != NULL */ -static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms); -static void -dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); -static int -dtdCopy(XML_Parser oldParser, - DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); -static int -copyEntityTable(XML_Parser oldParser, - HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); -static NAMED * -lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize); -static void FASTCALL -hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); -static void FASTCALL hashTableClear(HASH_TABLE *); -static void FASTCALL hashTableDestroy(HASH_TABLE *); -static void FASTCALL -hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); -static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *); - -static void FASTCALL -poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms); -static void FASTCALL poolClear(STRING_POOL *); -static void FASTCALL poolDestroy(STRING_POOL *); -static XML_Char * -poolAppend(STRING_POOL *pool, const ENCODING *enc, - const char *ptr, const char *end); -static XML_Char * -poolStoreString(STRING_POOL *pool, const ENCODING *enc, - const char *ptr, const char *end); -static XML_Bool FASTCALL poolGrow(STRING_POOL *pool); -static const XML_Char * FASTCALL -poolCopyString(STRING_POOL *pool, const XML_Char *s); -static const XML_Char * -poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n); -static const XML_Char * FASTCALL -poolAppendString(STRING_POOL *pool, const XML_Char *s); - -static int FASTCALL nextScaffoldPart(XML_Parser parser); -static XML_Content * build_model(XML_Parser parser); -static ELEMENT_TYPE * -getElementType(XML_Parser parser, const ENCODING *enc, - const char *ptr, const char *end); - -static unsigned long generate_hash_secret_salt(void); -static XML_Bool startParsing(XML_Parser parser); - -static XML_Parser -parserCreate(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep, - DTD *dtd); - -static void -parserInit(XML_Parser parser, const XML_Char *encodingName); - -#define poolStart(pool) ((pool)->start) -#define poolEnd(pool) ((pool)->ptr) -#define poolLength(pool) ((pool)->ptr - (pool)->start) -#define poolChop(pool) ((void)--(pool->ptr)) -#define poolLastChar(pool) (((pool)->ptr)[-1]) -#define poolDiscard(pool) ((pool)->ptr = (pool)->start) -#define poolFinish(pool) ((pool)->start = (pool)->ptr) -#define poolAppendChar(pool, c) \ - (((pool)->ptr == (pool)->end && !poolGrow(pool)) \ - ? 0 \ - : ((*((pool)->ptr)++ = c), 1)) - -struct XML_ParserStruct { - /* The first member must be userData so that the XML_GetUserData - macro works. */ - void *m_userData; - void *m_handlerArg; - char *m_buffer; - const XML_Memory_Handling_Suite m_mem; - /* first character to be parsed */ - const char *m_bufferPtr; - /* past last character to be parsed */ - char *m_bufferEnd; - /* allocated end of buffer */ - const char *m_bufferLim; - XML_Index m_parseEndByteIndex; - const char *m_parseEndPtr; - XML_Char *m_dataBuf; - XML_Char *m_dataBufEnd; - XML_StartElementHandler m_startElementHandler; - XML_EndElementHandler m_endElementHandler; - XML_CharacterDataHandler m_characterDataHandler; - XML_ProcessingInstructionHandler m_processingInstructionHandler; - XML_CommentHandler m_commentHandler; - XML_StartCdataSectionHandler m_startCdataSectionHandler; - XML_EndCdataSectionHandler m_endCdataSectionHandler; - XML_DefaultHandler m_defaultHandler; - XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler; - XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler; - XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler; - XML_NotationDeclHandler m_notationDeclHandler; - XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler; - XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler; - XML_NotStandaloneHandler m_notStandaloneHandler; - XML_ExternalEntityRefHandler m_externalEntityRefHandler; - XML_Parser m_externalEntityRefHandlerArg; - XML_SkippedEntityHandler m_skippedEntityHandler; - XML_UnknownEncodingHandler m_unknownEncodingHandler; - XML_ElementDeclHandler m_elementDeclHandler; - XML_AttlistDeclHandler m_attlistDeclHandler; - XML_EntityDeclHandler m_entityDeclHandler; - XML_XmlDeclHandler m_xmlDeclHandler; - const ENCODING *m_encoding; - INIT_ENCODING m_initEncoding; - const ENCODING *m_internalEncoding; - const XML_Char *m_protocolEncodingName; - XML_Bool m_ns; - XML_Bool m_ns_triplets; - void *m_unknownEncodingMem; - void *m_unknownEncodingData; - void *m_unknownEncodingHandlerData; - void (XMLCALL *m_unknownEncodingRelease)(void *); - PROLOG_STATE m_prologState; - Processor *m_processor; - enum XML_Error m_errorCode; - const char *m_eventPtr; - const char *m_eventEndPtr; - const char *m_positionPtr; - OPEN_INTERNAL_ENTITY *m_openInternalEntities; - OPEN_INTERNAL_ENTITY *m_freeInternalEntities; - XML_Bool m_defaultExpandInternalEntities; - int m_tagLevel; - ENTITY *m_declEntity; - const XML_Char *m_doctypeName; - const XML_Char *m_doctypeSysid; - const XML_Char *m_doctypePubid; - const XML_Char *m_declAttributeType; - const XML_Char *m_declNotationName; - const XML_Char *m_declNotationPublicId; - ELEMENT_TYPE *m_declElementType; - ATTRIBUTE_ID *m_declAttributeId; - XML_Bool m_declAttributeIsCdata; - XML_Bool m_declAttributeIsId; - DTD *m_dtd; - const XML_Char *m_curBase; - TAG *m_tagStack; - TAG *m_freeTagList; - BINDING *m_inheritedBindings; - BINDING *m_freeBindingList; - int m_attsSize; - int m_nSpecifiedAtts; - int m_idAttIndex; - ATTRIBUTE *m_atts; - NS_ATT *m_nsAtts; - unsigned long m_nsAttsVersion; - unsigned char m_nsAttsPower; -#ifdef XML_ATTR_INFO - XML_AttrInfo *m_attInfo; -#endif - POSITION m_position; - STRING_POOL m_tempPool; - STRING_POOL m_temp2Pool; - char *m_groupConnector; - unsigned int m_groupSize; - XML_Char m_namespaceSeparator; - XML_Parser m_parentParser; - XML_ParsingStatus m_parsingStatus; -#ifdef XML_DTD - XML_Bool m_isParamEntity; - XML_Bool m_useForeignDTD; - enum XML_ParamEntityParsing m_paramEntityParsing; -#endif - unsigned long m_hash_secret_salt; -}; - -#define MALLOC(s) (parser->m_mem.malloc_fcn((s))) -#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s))) -#define FREE(p) (parser->m_mem.free_fcn((p))) - -#define userData (parser->m_userData) -#define handlerArg (parser->m_handlerArg) -#define startElementHandler (parser->m_startElementHandler) -#define endElementHandler (parser->m_endElementHandler) -#define characterDataHandler (parser->m_characterDataHandler) -#define processingInstructionHandler \ - (parser->m_processingInstructionHandler) -#define commentHandler (parser->m_commentHandler) -#define startCdataSectionHandler \ - (parser->m_startCdataSectionHandler) -#define endCdataSectionHandler (parser->m_endCdataSectionHandler) -#define defaultHandler (parser->m_defaultHandler) -#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler) -#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler) -#define unparsedEntityDeclHandler \ - (parser->m_unparsedEntityDeclHandler) -#define notationDeclHandler (parser->m_notationDeclHandler) -#define startNamespaceDeclHandler \ - (parser->m_startNamespaceDeclHandler) -#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler) -#define notStandaloneHandler (parser->m_notStandaloneHandler) -#define externalEntityRefHandler \ - (parser->m_externalEntityRefHandler) -#define externalEntityRefHandlerArg \ - (parser->m_externalEntityRefHandlerArg) -#define internalEntityRefHandler \ - (parser->m_internalEntityRefHandler) -#define skippedEntityHandler (parser->m_skippedEntityHandler) -#define unknownEncodingHandler (parser->m_unknownEncodingHandler) -#define elementDeclHandler (parser->m_elementDeclHandler) -#define attlistDeclHandler (parser->m_attlistDeclHandler) -#define entityDeclHandler (parser->m_entityDeclHandler) -#define xmlDeclHandler (parser->m_xmlDeclHandler) -#define encoding (parser->m_encoding) -#define initEncoding (parser->m_initEncoding) -#define internalEncoding (parser->m_internalEncoding) -#define unknownEncodingMem (parser->m_unknownEncodingMem) -#define unknownEncodingData (parser->m_unknownEncodingData) -#define unknownEncodingHandlerData \ - (parser->m_unknownEncodingHandlerData) -#define unknownEncodingRelease (parser->m_unknownEncodingRelease) -#define protocolEncodingName (parser->m_protocolEncodingName) -#define ns (parser->m_ns) -#define ns_triplets (parser->m_ns_triplets) -#define prologState (parser->m_prologState) -#define processor (parser->m_processor) -#define errorCode (parser->m_errorCode) -#define eventPtr (parser->m_eventPtr) -#define eventEndPtr (parser->m_eventEndPtr) -#define positionPtr (parser->m_positionPtr) -#define position (parser->m_position) -#define openInternalEntities (parser->m_openInternalEntities) -#define freeInternalEntities (parser->m_freeInternalEntities) -#define defaultExpandInternalEntities \ - (parser->m_defaultExpandInternalEntities) -#define tagLevel (parser->m_tagLevel) -#define buffer (parser->m_buffer) -#define bufferPtr (parser->m_bufferPtr) -#define bufferEnd (parser->m_bufferEnd) -#define parseEndByteIndex (parser->m_parseEndByteIndex) -#define parseEndPtr (parser->m_parseEndPtr) -#define bufferLim (parser->m_bufferLim) -#define dataBuf (parser->m_dataBuf) -#define dataBufEnd (parser->m_dataBufEnd) -#define _dtd (parser->m_dtd) -#define curBase (parser->m_curBase) -#define declEntity (parser->m_declEntity) -#define doctypeName (parser->m_doctypeName) -#define doctypeSysid (parser->m_doctypeSysid) -#define doctypePubid (parser->m_doctypePubid) -#define declAttributeType (parser->m_declAttributeType) -#define declNotationName (parser->m_declNotationName) -#define declNotationPublicId (parser->m_declNotationPublicId) -#define declElementType (parser->m_declElementType) -#define declAttributeId (parser->m_declAttributeId) -#define declAttributeIsCdata (parser->m_declAttributeIsCdata) -#define declAttributeIsId (parser->m_declAttributeIsId) -#define freeTagList (parser->m_freeTagList) -#define freeBindingList (parser->m_freeBindingList) -#define inheritedBindings (parser->m_inheritedBindings) -#define tagStack (parser->m_tagStack) -#define atts (parser->m_atts) -#define attsSize (parser->m_attsSize) -#define nSpecifiedAtts (parser->m_nSpecifiedAtts) -#define idAttIndex (parser->m_idAttIndex) -#define nsAtts (parser->m_nsAtts) -#define nsAttsVersion (parser->m_nsAttsVersion) -#define nsAttsPower (parser->m_nsAttsPower) -#define attInfo (parser->m_attInfo) -#define tempPool (parser->m_tempPool) -#define temp2Pool (parser->m_temp2Pool) -#define groupConnector (parser->m_groupConnector) -#define groupSize (parser->m_groupSize) -#define namespaceSeparator (parser->m_namespaceSeparator) -#define parentParser (parser->m_parentParser) -#define ps_parsing (parser->m_parsingStatus.parsing) -#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer) -#ifdef XML_DTD -#define isParamEntity (parser->m_isParamEntity) -#define useForeignDTD (parser->m_useForeignDTD) -#define paramEntityParsing (parser->m_paramEntityParsing) -#endif /* XML_DTD */ -#define hash_secret_salt (parser->m_hash_secret_salt) - -XML_Parser XMLCALL -XML_ParserCreate(const XML_Char *encodingName) -{ - return XML_ParserCreate_MM(encodingName, NULL, NULL); -} - -XML_Parser XMLCALL -XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) -{ - XML_Char tmp[2]; - *tmp = nsSep; - return XML_ParserCreate_MM(encodingName, NULL, tmp); -} - -static const XML_Char implicitContext[] = { - ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, ASCII_t, ASCII_t, ASCII_p, - ASCII_COLON, ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w, - ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g, - ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9, - ASCII_9, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e, - ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0' -}; - -static unsigned long -generate_hash_secret_salt(void) -{ - unsigned int seed = time(NULL) % UINT_MAX; - srand(seed); - return rand(); -} - -static XML_Bool /* only valid for root parser */ -startParsing(XML_Parser parser) -{ - /* hash functions must be initialized before setContext() is called */ - if (hash_secret_salt == 0) - hash_secret_salt = generate_hash_secret_salt(); - if (ns) { - /* implicit context only set for root parser, since child - parsers (i.e. external entity parsers) will inherit it - */ - return setContext(parser, implicitContext); - } - return XML_TRUE; -} - -XML_Parser XMLCALL -XML_ParserCreate_MM(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep) -{ - return parserCreate(encodingName, memsuite, nameSep, NULL); -} - -static XML_Parser -parserCreate(const XML_Char *encodingName, - const XML_Memory_Handling_Suite *memsuite, - const XML_Char *nameSep, - DTD *dtd) -{ - XML_Parser parser; - - if (memsuite) { - XML_Memory_Handling_Suite *mtemp; - parser = (XML_Parser) - memsuite->malloc_fcn(sizeof(struct XML_ParserStruct)); - if (parser != NULL) { - mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); - mtemp->malloc_fcn = memsuite->malloc_fcn; - mtemp->realloc_fcn = memsuite->realloc_fcn; - mtemp->free_fcn = memsuite->free_fcn; - } - } - else { - XML_Memory_Handling_Suite *mtemp; - parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct)); - if (parser != NULL) { - mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); - mtemp->malloc_fcn = malloc; - mtemp->realloc_fcn = realloc; - mtemp->free_fcn = free; - } - } - - if (!parser) - return parser; - - buffer = NULL; - bufferLim = NULL; - - attsSize = INIT_ATTS_SIZE; - atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE)); - if (atts == NULL) { - FREE(parser); - return NULL; - } -#ifdef XML_ATTR_INFO - attInfo = (XML_AttrInfo*)MALLOC(attsSize * sizeof(XML_AttrInfo)); - if (attInfo == NULL) { - FREE(atts); - FREE(parser); - return NULL; - } -#endif - dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char)); - if (dataBuf == NULL) { - FREE(atts); -#ifdef XML_ATTR_INFO - FREE(attInfo); -#endif - FREE(parser); - return NULL; - } - dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE; - - if (dtd) - _dtd = dtd; - else { - _dtd = dtdCreate(&parser->m_mem); - if (_dtd == NULL) { - FREE(dataBuf); - FREE(atts); -#ifdef XML_ATTR_INFO - FREE(attInfo); -#endif - FREE(parser); - return NULL; - } - } - - freeBindingList = NULL; - freeTagList = NULL; - freeInternalEntities = NULL; - - groupSize = 0; - groupConnector = NULL; - - unknownEncodingHandler = NULL; - unknownEncodingHandlerData = NULL; - - namespaceSeparator = ASCII_EXCL; - ns = XML_FALSE; - ns_triplets = XML_FALSE; - - nsAtts = NULL; - nsAttsVersion = 0; - nsAttsPower = 0; - - poolInit(&tempPool, &(parser->m_mem)); - poolInit(&temp2Pool, &(parser->m_mem)); - parserInit(parser, encodingName); - - if (encodingName && !protocolEncodingName) { - XML_ParserFree(parser); - return NULL; - } - - if (nameSep) { - ns = XML_TRUE; - internalEncoding = XmlGetInternalEncodingNS(); - namespaceSeparator = *nameSep; - } - else { - internalEncoding = XmlGetInternalEncoding(); - } - - return parser; -} - -static void -parserInit(XML_Parser parser, const XML_Char *encodingName) -{ - processor = prologInitProcessor; - XmlPrologStateInit(&prologState); - protocolEncodingName = (encodingName != NULL - ? poolCopyString(&tempPool, encodingName) - : NULL); - curBase = NULL; - XmlInitEncoding(&initEncoding, &encoding, 0); - userData = NULL; - handlerArg = NULL; - startElementHandler = NULL; - endElementHandler = NULL; - characterDataHandler = NULL; - processingInstructionHandler = NULL; - commentHandler = NULL; - startCdataSectionHandler = NULL; - endCdataSectionHandler = NULL; - defaultHandler = NULL; - startDoctypeDeclHandler = NULL; - endDoctypeDeclHandler = NULL; - unparsedEntityDeclHandler = NULL; - notationDeclHandler = NULL; - startNamespaceDeclHandler = NULL; - endNamespaceDeclHandler = NULL; - notStandaloneHandler = NULL; - externalEntityRefHandler = NULL; - externalEntityRefHandlerArg = parser; - skippedEntityHandler = NULL; - elementDeclHandler = NULL; - attlistDeclHandler = NULL; - entityDeclHandler = NULL; - xmlDeclHandler = NULL; - bufferPtr = buffer; - bufferEnd = buffer; - parseEndByteIndex = 0; - parseEndPtr = NULL; - declElementType = NULL; - declAttributeId = NULL; - declEntity = NULL; - doctypeName = NULL; - doctypeSysid = NULL; - doctypePubid = NULL; - declAttributeType = NULL; - declNotationName = NULL; - declNotationPublicId = NULL; - declAttributeIsCdata = XML_FALSE; - declAttributeIsId = XML_FALSE; - memset(&position, 0, sizeof(POSITION)); - errorCode = XML_ERROR_NONE; - eventPtr = NULL; - eventEndPtr = NULL; - positionPtr = NULL; - openInternalEntities = NULL; - defaultExpandInternalEntities = XML_TRUE; - tagLevel = 0; - tagStack = NULL; - inheritedBindings = NULL; - nSpecifiedAtts = 0; - unknownEncodingMem = NULL; - unknownEncodingRelease = NULL; - unknownEncodingData = NULL; - parentParser = NULL; - ps_parsing = XML_INITIALIZED; -#ifdef XML_DTD - isParamEntity = XML_FALSE; - useForeignDTD = XML_FALSE; - paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; -#endif - hash_secret_salt = 0; -} - -/* moves list of bindings to freeBindingList */ -static void FASTCALL -moveToFreeBindingList(XML_Parser parser, BINDING *bindings) -{ - while (bindings) { - BINDING *b = bindings; - bindings = bindings->nextTagBinding; - b->nextTagBinding = freeBindingList; - freeBindingList = b; - } -} - -XML_Bool XMLCALL -XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) -{ - TAG *tStk; - OPEN_INTERNAL_ENTITY *openEntityList; - if (parentParser) - return XML_FALSE; - /* move tagStack to freeTagList */ - tStk = tagStack; - while (tStk) { - TAG *tag = tStk; - tStk = tStk->parent; - tag->parent = freeTagList; - moveToFreeBindingList(parser, tag->bindings); - tag->bindings = NULL; - freeTagList = tag; - } - /* move openInternalEntities to freeInternalEntities */ - openEntityList = openInternalEntities; - while (openEntityList) { - OPEN_INTERNAL_ENTITY *openEntity = openEntityList; - openEntityList = openEntity->next; - openEntity->next = freeInternalEntities; - freeInternalEntities = openEntity; - } - moveToFreeBindingList(parser, inheritedBindings); - FREE(unknownEncodingMem); - if (unknownEncodingRelease) - unknownEncodingRelease(unknownEncodingData); - poolClear(&tempPool); - poolClear(&temp2Pool); - parserInit(parser, encodingName); - dtdReset(_dtd, &parser->m_mem); - return XML_TRUE; -} - -enum XML_Status XMLCALL -XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) -{ - /* Block after XML_Parse()/XML_ParseBuffer() has been called. - XXX There's no way for the caller to determine which of the - XXX possible error cases caused the XML_STATUS_ERROR return. - */ - if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) - return XML_STATUS_ERROR; - if (encodingName == NULL) - protocolEncodingName = NULL; - else { - protocolEncodingName = poolCopyString(&tempPool, encodingName); - if (!protocolEncodingName) - return XML_STATUS_ERROR; - } - return XML_STATUS_OK; -} - -XML_Parser XMLCALL -XML_ExternalEntityParserCreate(XML_Parser oldParser, - const XML_Char *context, - const XML_Char *encodingName) -{ - XML_Parser parser = oldParser; - DTD *newDtd = NULL; - DTD *oldDtd = _dtd; - XML_StartElementHandler oldStartElementHandler = startElementHandler; - XML_EndElementHandler oldEndElementHandler = endElementHandler; - XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler; - XML_ProcessingInstructionHandler oldProcessingInstructionHandler - = processingInstructionHandler; - XML_CommentHandler oldCommentHandler = commentHandler; - XML_StartCdataSectionHandler oldStartCdataSectionHandler - = startCdataSectionHandler; - XML_EndCdataSectionHandler oldEndCdataSectionHandler - = endCdataSectionHandler; - XML_DefaultHandler oldDefaultHandler = defaultHandler; - XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler - = unparsedEntityDeclHandler; - XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler; - XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler - = startNamespaceDeclHandler; - XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler - = endNamespaceDeclHandler; - XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler; - XML_ExternalEntityRefHandler oldExternalEntityRefHandler - = externalEntityRefHandler; - XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler; - XML_UnknownEncodingHandler oldUnknownEncodingHandler - = unknownEncodingHandler; - XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler; - XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler; - XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler; - XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler; - ELEMENT_TYPE * oldDeclElementType = declElementType; - - void *oldUserData = userData; - void *oldHandlerArg = handlerArg; - XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities; - XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg; -#ifdef XML_DTD - enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing; - int oldInEntityValue = prologState.inEntityValue; -#endif - XML_Bool oldns_triplets = ns_triplets; - /* Note that the new parser shares the same hash secret as the old - parser, so that dtdCopy and copyEntityTable can lookup values - from hash tables associated with either parser without us having - to worry which hash secrets each table has. - */ - unsigned long oldhash_secret_salt = hash_secret_salt; - -#ifdef XML_DTD - if (!context) - newDtd = oldDtd; -#endif /* XML_DTD */ - - /* Note that the magical uses of the pre-processor to make field - access look more like C++ require that `parser' be overwritten - here. This makes this function more painful to follow than it - would be otherwise. - */ - if (ns) { - XML_Char tmp[2]; - *tmp = namespaceSeparator; - parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd); - } - else { - parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd); - } - - if (!parser) - return NULL; - - startElementHandler = oldStartElementHandler; - endElementHandler = oldEndElementHandler; - characterDataHandler = oldCharacterDataHandler; - processingInstructionHandler = oldProcessingInstructionHandler; - commentHandler = oldCommentHandler; - startCdataSectionHandler = oldStartCdataSectionHandler; - endCdataSectionHandler = oldEndCdataSectionHandler; - defaultHandler = oldDefaultHandler; - unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler; - notationDeclHandler = oldNotationDeclHandler; - startNamespaceDeclHandler = oldStartNamespaceDeclHandler; - endNamespaceDeclHandler = oldEndNamespaceDeclHandler; - notStandaloneHandler = oldNotStandaloneHandler; - externalEntityRefHandler = oldExternalEntityRefHandler; - skippedEntityHandler = oldSkippedEntityHandler; - unknownEncodingHandler = oldUnknownEncodingHandler; - elementDeclHandler = oldElementDeclHandler; - attlistDeclHandler = oldAttlistDeclHandler; - entityDeclHandler = oldEntityDeclHandler; - xmlDeclHandler = oldXmlDeclHandler; - declElementType = oldDeclElementType; - userData = oldUserData; - if (oldUserData == oldHandlerArg) - handlerArg = userData; - else - handlerArg = parser; - if (oldExternalEntityRefHandlerArg != oldParser) - externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; - defaultExpandInternalEntities = oldDefaultExpandInternalEntities; - ns_triplets = oldns_triplets; - hash_secret_salt = oldhash_secret_salt; - parentParser = oldParser; -#ifdef XML_DTD - paramEntityParsing = oldParamEntityParsing; - prologState.inEntityValue = oldInEntityValue; - if (context) { -#endif /* XML_DTD */ - if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem) - || !setContext(parser, context)) { - XML_ParserFree(parser); - return NULL; - } - processor = externalEntityInitProcessor; -#ifdef XML_DTD - } - else { - /* The DTD instance referenced by _dtd is shared between the document's - root parser and external PE parsers, therefore one does not need to - call setContext. In addition, one also *must* not call setContext, - because this would overwrite existing prefix->binding pointers in - _dtd with ones that get destroyed with the external PE parser. - This would leave those prefixes with dangling pointers. - */ - isParamEntity = XML_TRUE; - XmlPrologStateInitExternalEntity(&prologState); - processor = externalParEntInitProcessor; - } -#endif /* XML_DTD */ - return parser; -} - -static void FASTCALL -destroyBindings(BINDING *bindings, XML_Parser parser) -{ - for (;;) { - BINDING *b = bindings; - if (!b) - break; - bindings = b->nextTagBinding; - FREE(b->uri); - FREE(b); - } -} - -void XMLCALL -XML_ParserFree(XML_Parser parser) -{ - TAG *tagList; - OPEN_INTERNAL_ENTITY *entityList; - if (parser == NULL) - return; - /* free tagStack and freeTagList */ - tagList = tagStack; - for (;;) { - TAG *p; - if (tagList == NULL) { - if (freeTagList == NULL) - break; - tagList = freeTagList; - freeTagList = NULL; - } - p = tagList; - tagList = tagList->parent; - FREE(p->buf); - destroyBindings(p->bindings, parser); - FREE(p); - } - /* free openInternalEntities and freeInternalEntities */ - entityList = openInternalEntities; - for (;;) { - OPEN_INTERNAL_ENTITY *openEntity; - if (entityList == NULL) { - if (freeInternalEntities == NULL) - break; - entityList = freeInternalEntities; - freeInternalEntities = NULL; - } - openEntity = entityList; - entityList = entityList->next; - FREE(openEntity); - } - - destroyBindings(freeBindingList, parser); - destroyBindings(inheritedBindings, parser); - poolDestroy(&tempPool); - poolDestroy(&temp2Pool); -#ifdef XML_DTD - /* external parameter entity parsers share the DTD structure - parser->m_dtd with the root parser, so we must not destroy it - */ - if (!isParamEntity && _dtd) -#else - if (_dtd) -#endif /* XML_DTD */ - dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem); - FREE((void *)atts); -#ifdef XML_ATTR_INFO - FREE((void *)attInfo); -#endif - FREE(groupConnector); - FREE(buffer); - FREE(dataBuf); - FREE(nsAtts); - FREE(unknownEncodingMem); - if (unknownEncodingRelease) - unknownEncodingRelease(unknownEncodingData); - FREE(parser); -} - -void XMLCALL -XML_UseParserAsHandlerArg(XML_Parser parser) -{ - handlerArg = parser; -} - -enum XML_Error XMLCALL -XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD) -{ -#ifdef XML_DTD - /* block after XML_Parse()/XML_ParseBuffer() has been called */ - if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) - return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING; - useForeignDTD = useDTD; - return XML_ERROR_NONE; -#else - return XML_ERROR_FEATURE_REQUIRES_XML_DTD; -#endif -} - -void XMLCALL -XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) -{ - /* block after XML_Parse()/XML_ParseBuffer() has been called */ - if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) - return; - ns_triplets = do_nst ? XML_TRUE : XML_FALSE; -} - -void XMLCALL -XML_SetUserData(XML_Parser parser, void *p) -{ - if (handlerArg == userData) - handlerArg = userData = p; - else - userData = p; -} - -enum XML_Status XMLCALL -XML_SetBase(XML_Parser parser, const XML_Char *p) -{ - if (p) { - p = poolCopyString(&_dtd->pool, p); - if (!p) - return XML_STATUS_ERROR; - curBase = p; - } - else - curBase = NULL; - return XML_STATUS_OK; -} - -const XML_Char * XMLCALL -XML_GetBase(XML_Parser parser) -{ - return curBase; -} - -int XMLCALL -XML_GetSpecifiedAttributeCount(XML_Parser parser) -{ - return nSpecifiedAtts; -} - -int XMLCALL -XML_GetIdAttributeIndex(XML_Parser parser) -{ - return idAttIndex; -} - -#ifdef XML_ATTR_INFO -const XML_AttrInfo * XMLCALL -XML_GetAttributeInfo(XML_Parser parser) -{ - return attInfo; -} -#endif - -void XMLCALL -XML_SetElementHandler(XML_Parser parser, - XML_StartElementHandler start, - XML_EndElementHandler end) -{ - startElementHandler = start; - endElementHandler = end; -} - -void XMLCALL -XML_SetStartElementHandler(XML_Parser parser, - XML_StartElementHandler start) { - startElementHandler = start; -} - -void XMLCALL -XML_SetEndElementHandler(XML_Parser parser, - XML_EndElementHandler end) { - endElementHandler = end; -} - -void XMLCALL -XML_SetCharacterDataHandler(XML_Parser parser, - XML_CharacterDataHandler handler) -{ - characterDataHandler = handler; -} - -void XMLCALL -XML_SetProcessingInstructionHandler(XML_Parser parser, - XML_ProcessingInstructionHandler handler) -{ - processingInstructionHandler = handler; -} - -void XMLCALL -XML_SetCommentHandler(XML_Parser parser, - XML_CommentHandler handler) -{ - commentHandler = handler; -} - -void XMLCALL -XML_SetCdataSectionHandler(XML_Parser parser, - XML_StartCdataSectionHandler start, - XML_EndCdataSectionHandler end) -{ - startCdataSectionHandler = start; - endCdataSectionHandler = end; -} - -void XMLCALL -XML_SetStartCdataSectionHandler(XML_Parser parser, - XML_StartCdataSectionHandler start) { - startCdataSectionHandler = start; -} - -void XMLCALL -XML_SetEndCdataSectionHandler(XML_Parser parser, - XML_EndCdataSectionHandler end) { - endCdataSectionHandler = end; -} - -void XMLCALL -XML_SetDefaultHandler(XML_Parser parser, - XML_DefaultHandler handler) -{ - defaultHandler = handler; - defaultExpandInternalEntities = XML_FALSE; -} - -void XMLCALL -XML_SetDefaultHandlerExpand(XML_Parser parser, - XML_DefaultHandler handler) -{ - defaultHandler = handler; - defaultExpandInternalEntities = XML_TRUE; -} - -void XMLCALL -XML_SetDoctypeDeclHandler(XML_Parser parser, - XML_StartDoctypeDeclHandler start, - XML_EndDoctypeDeclHandler end) -{ - startDoctypeDeclHandler = start; - endDoctypeDeclHandler = end; -} - -void XMLCALL -XML_SetStartDoctypeDeclHandler(XML_Parser parser, - XML_StartDoctypeDeclHandler start) { - startDoctypeDeclHandler = start; -} - -void XMLCALL -XML_SetEndDoctypeDeclHandler(XML_Parser parser, - XML_EndDoctypeDeclHandler end) { - endDoctypeDeclHandler = end; -} - -void XMLCALL -XML_SetUnparsedEntityDeclHandler(XML_Parser parser, - XML_UnparsedEntityDeclHandler handler) -{ - unparsedEntityDeclHandler = handler; -} - -void XMLCALL -XML_SetNotationDeclHandler(XML_Parser parser, - XML_NotationDeclHandler handler) -{ - notationDeclHandler = handler; -} - -void XMLCALL -XML_SetNamespaceDeclHandler(XML_Parser parser, - XML_StartNamespaceDeclHandler start, - XML_EndNamespaceDeclHandler end) -{ - startNamespaceDeclHandler = start; - endNamespaceDeclHandler = end; -} - -void XMLCALL -XML_SetStartNamespaceDeclHandler(XML_Parser parser, - XML_StartNamespaceDeclHandler start) { - startNamespaceDeclHandler = start; -} - -void XMLCALL -XML_SetEndNamespaceDeclHandler(XML_Parser parser, - XML_EndNamespaceDeclHandler end) { - endNamespaceDeclHandler = end; -} - -void XMLCALL -XML_SetNotStandaloneHandler(XML_Parser parser, - XML_NotStandaloneHandler handler) -{ - notStandaloneHandler = handler; -} - -void XMLCALL -XML_SetExternalEntityRefHandler(XML_Parser parser, - XML_ExternalEntityRefHandler handler) -{ - externalEntityRefHandler = handler; -} - -void XMLCALL -XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg) -{ - if (arg) - externalEntityRefHandlerArg = (XML_Parser)arg; - else - externalEntityRefHandlerArg = parser; -} - -void XMLCALL -XML_SetSkippedEntityHandler(XML_Parser parser, - XML_SkippedEntityHandler handler) -{ - skippedEntityHandler = handler; -} - -void XMLCALL -XML_SetUnknownEncodingHandler(XML_Parser parser, - XML_UnknownEncodingHandler handler, - void *data) -{ - unknownEncodingHandler = handler; - unknownEncodingHandlerData = data; -} - -void XMLCALL -XML_SetElementDeclHandler(XML_Parser parser, - XML_ElementDeclHandler eldecl) -{ - elementDeclHandler = eldecl; -} - -void XMLCALL -XML_SetAttlistDeclHandler(XML_Parser parser, - XML_AttlistDeclHandler attdecl) -{ - attlistDeclHandler = attdecl; -} - -void XMLCALL -XML_SetEntityDeclHandler(XML_Parser parser, - XML_EntityDeclHandler handler) -{ - entityDeclHandler = handler; -} - -void XMLCALL -XML_SetXmlDeclHandler(XML_Parser parser, - XML_XmlDeclHandler handler) { - xmlDeclHandler = handler; -} - -int XMLCALL -XML_SetParamEntityParsing(XML_Parser parser, - enum XML_ParamEntityParsing peParsing) -{ - /* block after XML_Parse()/XML_ParseBuffer() has been called */ - if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) - return 0; -#ifdef XML_DTD - paramEntityParsing = peParsing; - return 1; -#else - return peParsing == XML_PARAM_ENTITY_PARSING_NEVER; -#endif -} - -int XMLCALL -XML_SetHashSalt(XML_Parser parser, - unsigned long hash_salt) -{ - /* block after XML_Parse()/XML_ParseBuffer() has been called */ - if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) - return 0; - hash_secret_salt = hash_salt; - return 1; -} - -enum XML_Status XMLCALL -XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) -{ - switch (ps_parsing) { - case XML_SUSPENDED: - errorCode = XML_ERROR_SUSPENDED; - return XML_STATUS_ERROR; - case XML_FINISHED: - errorCode = XML_ERROR_FINISHED; - return XML_STATUS_ERROR; - case XML_INITIALIZED: - if (parentParser == NULL && !startParsing(parser)) { - errorCode = XML_ERROR_NO_MEMORY; - return XML_STATUS_ERROR; - } - default: - ps_parsing = XML_PARSING; - } - - if (len == 0) { - ps_finalBuffer = (XML_Bool)isFinal; - if (!isFinal) - return XML_STATUS_OK; - positionPtr = bufferPtr; - parseEndPtr = bufferEnd; - - /* If data are left over from last buffer, and we now know that these - data are the final chunk of input, then we have to check them again - to detect errors based on that fact. - */ - errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr); - - if (errorCode == XML_ERROR_NONE) { - switch (ps_parsing) { - case XML_SUSPENDED: - XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); - positionPtr = bufferPtr; - return XML_STATUS_SUSPENDED; - case XML_INITIALIZED: - case XML_PARSING: - ps_parsing = XML_FINISHED; - /* fall through */ - default: - return XML_STATUS_OK; - } - } - eventEndPtr = eventPtr; - processor = errorProcessor; - return XML_STATUS_ERROR; - } -#ifndef XML_CONTEXT_BYTES - else if (bufferPtr == bufferEnd) { - const char *end; - int nLeftOver; - enum XML_Error result; - parseEndByteIndex += len; - positionPtr = s; - ps_finalBuffer = (XML_Bool)isFinal; - - errorCode = processor(parser, s, parseEndPtr = s + len, &end); - - if (errorCode != XML_ERROR_NONE) { - eventEndPtr = eventPtr; - processor = errorProcessor; - return XML_STATUS_ERROR; - } - else { - switch (ps_parsing) { - case XML_SUSPENDED: - result = XML_STATUS_SUSPENDED; - break; - case XML_INITIALIZED: - case XML_PARSING: - if (isFinal) { - ps_parsing = XML_FINISHED; - return XML_STATUS_OK; - } - /* fall through */ - default: - result = XML_STATUS_OK; - } - } - - XmlUpdatePosition(encoding, positionPtr, end, &position); - nLeftOver = s + len - end; - if (nLeftOver) { - if (buffer == NULL || nLeftOver > bufferLim - buffer) { - /* FIXME avoid integer overflow */ - char *temp; - temp = (buffer == NULL - ? (char *)MALLOC(len * 2) - : (char *)REALLOC(buffer, len * 2)); - if (temp == NULL) { - errorCode = XML_ERROR_NO_MEMORY; - eventPtr = eventEndPtr = NULL; - processor = errorProcessor; - return XML_STATUS_ERROR; - } - buffer = temp; - bufferLim = buffer + len * 2; - } - memcpy(buffer, end, nLeftOver); - } - bufferPtr = buffer; - bufferEnd = buffer + nLeftOver; - positionPtr = bufferPtr; - parseEndPtr = bufferEnd; - eventPtr = bufferPtr; - eventEndPtr = bufferPtr; - return result; - } -#endif /* not defined XML_CONTEXT_BYTES */ - else { - void *buff = XML_GetBuffer(parser, len); - if (buff == NULL) - return XML_STATUS_ERROR; - else { - memcpy(buff, s, len); - return XML_ParseBuffer(parser, len, isFinal); - } - } -} - -enum XML_Status XMLCALL -XML_ParseBuffer(XML_Parser parser, int len, int isFinal) -{ - const char *start; - enum XML_Status result = XML_STATUS_OK; - - switch (ps_parsing) { - case XML_SUSPENDED: - errorCode = XML_ERROR_SUSPENDED; - return XML_STATUS_ERROR; - case XML_FINISHED: - errorCode = XML_ERROR_FINISHED; - return XML_STATUS_ERROR; - case XML_INITIALIZED: - if (parentParser == NULL && !startParsing(parser)) { - errorCode = XML_ERROR_NO_MEMORY; - return XML_STATUS_ERROR; - } - default: - ps_parsing = XML_PARSING; - } - - start = bufferPtr; - positionPtr = start; - bufferEnd += len; - parseEndPtr = bufferEnd; - parseEndByteIndex += len; - ps_finalBuffer = (XML_Bool)isFinal; - - errorCode = processor(parser, start, parseEndPtr, &bufferPtr); - - if (errorCode != XML_ERROR_NONE) { - eventEndPtr = eventPtr; - processor = errorProcessor; - return XML_STATUS_ERROR; - } - else { - switch (ps_parsing) { - case XML_SUSPENDED: - result = XML_STATUS_SUSPENDED; - break; - case XML_INITIALIZED: - case XML_PARSING: - if (isFinal) { - ps_parsing = XML_FINISHED; - return result; - } - default: ; /* should not happen */ - } - } - - XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); - positionPtr = bufferPtr; - return result; -} - -void * XMLCALL -XML_GetBuffer(XML_Parser parser, int len) -{ - switch (ps_parsing) { - case XML_SUSPENDED: - errorCode = XML_ERROR_SUSPENDED; - return NULL; - case XML_FINISHED: - errorCode = XML_ERROR_FINISHED; - return NULL; - default: ; - } - - if (len > bufferLim - bufferEnd) { - /* FIXME avoid integer overflow */ - int neededSize = len + (int)(bufferEnd - bufferPtr); -#ifdef XML_CONTEXT_BYTES - int keep = (int)(bufferPtr - buffer); - - if (keep > XML_CONTEXT_BYTES) - keep = XML_CONTEXT_BYTES; - neededSize += keep; -#endif /* defined XML_CONTEXT_BYTES */ - if (neededSize <= bufferLim - buffer) { -#ifdef XML_CONTEXT_BYTES - if (keep < bufferPtr - buffer) { - int offset = (int)(bufferPtr - buffer) - keep; - memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep); - bufferEnd -= offset; - bufferPtr -= offset; - } -#else - memmove(buffer, bufferPtr, bufferEnd - bufferPtr); - bufferEnd = buffer + (bufferEnd - bufferPtr); - bufferPtr = buffer; -#endif /* not defined XML_CONTEXT_BYTES */ - } - else { - char *newBuf; - int bufferSize = (int)(bufferLim - bufferPtr); - if (bufferSize == 0) - bufferSize = INIT_BUFFER_SIZE; - do { - bufferSize *= 2; - } while (bufferSize < neededSize); - newBuf = (char *)MALLOC(bufferSize); - if (newBuf == 0) { - errorCode = XML_ERROR_NO_MEMORY; - return NULL; - } - bufferLim = newBuf + bufferSize; -#ifdef XML_CONTEXT_BYTES - if (bufferPtr) { - int keep = (int)(bufferPtr - buffer); - if (keep > XML_CONTEXT_BYTES) - keep = XML_CONTEXT_BYTES; - memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep); - FREE(buffer); - buffer = newBuf; - bufferEnd = buffer + (bufferEnd - bufferPtr) + keep; - bufferPtr = buffer + keep; - } - else { - bufferEnd = newBuf + (bufferEnd - bufferPtr); - bufferPtr = buffer = newBuf; - } -#else - if (bufferPtr) { - memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr); - FREE(buffer); - } - bufferEnd = newBuf + (bufferEnd - bufferPtr); - bufferPtr = buffer = newBuf; -#endif /* not defined XML_CONTEXT_BYTES */ - } - eventPtr = eventEndPtr = NULL; - positionPtr = NULL; - } - return bufferEnd; -} - -enum XML_Status XMLCALL -XML_StopParser(XML_Parser parser, XML_Bool resumable) -{ - switch (ps_parsing) { - case XML_SUSPENDED: - if (resumable) { - errorCode = XML_ERROR_SUSPENDED; - return XML_STATUS_ERROR; - } - ps_parsing = XML_FINISHED; - break; - case XML_FINISHED: - errorCode = XML_ERROR_FINISHED; - return XML_STATUS_ERROR; - default: - if (resumable) { -#ifdef XML_DTD - if (isParamEntity) { - errorCode = XML_ERROR_SUSPEND_PE; - return XML_STATUS_ERROR; - } -#endif - ps_parsing = XML_SUSPENDED; - } - else - ps_parsing = XML_FINISHED; - } - return XML_STATUS_OK; -} - -enum XML_Status XMLCALL -XML_ResumeParser(XML_Parser parser) -{ - enum XML_Status result = XML_STATUS_OK; - - if (ps_parsing != XML_SUSPENDED) { - errorCode = XML_ERROR_NOT_SUSPENDED; - return XML_STATUS_ERROR; - } - ps_parsing = XML_PARSING; - - errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr); - - if (errorCode != XML_ERROR_NONE) { - eventEndPtr = eventPtr; - processor = errorProcessor; - return XML_STATUS_ERROR; - } - else { - switch (ps_parsing) { - case XML_SUSPENDED: - result = XML_STATUS_SUSPENDED; - break; - case XML_INITIALIZED: - case XML_PARSING: - if (ps_finalBuffer) { - ps_parsing = XML_FINISHED; - return result; - } - default: ; - } - } - - XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); - positionPtr = bufferPtr; - return result; -} - -void XMLCALL -XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status) -{ - assert(status != NULL); - *status = parser->m_parsingStatus; -} - -enum XML_Error XMLCALL -XML_GetErrorCode(XML_Parser parser) -{ - return errorCode; -} - -XML_Index XMLCALL -XML_GetCurrentByteIndex(XML_Parser parser) -{ - if (eventPtr) - return parseEndByteIndex - (parseEndPtr - eventPtr); - return -1; -} - -int XMLCALL -XML_GetCurrentByteCount(XML_Parser parser) -{ - if (eventEndPtr && eventPtr) - return (int)(eventEndPtr - eventPtr); - return 0; -} - -const char * XMLCALL -XML_GetInputContext(XML_Parser parser, int *offset, int *size) -{ -#ifdef XML_CONTEXT_BYTES - if (eventPtr && buffer) { - *offset = (int)(eventPtr - buffer); - *size = (int)(bufferEnd - buffer); - return buffer; - } -#endif /* defined XML_CONTEXT_BYTES */ - return (char *) 0; -} - -XML_Size XMLCALL -XML_GetCurrentLineNumber(XML_Parser parser) -{ - if (eventPtr && eventPtr >= positionPtr) { - XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); - positionPtr = eventPtr; - } - return position.lineNumber + 1; -} - -XML_Size XMLCALL -XML_GetCurrentColumnNumber(XML_Parser parser) -{ - if (eventPtr && eventPtr >= positionPtr) { - XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); - positionPtr = eventPtr; - } - return position.columnNumber; -} - -void XMLCALL -XML_FreeContentModel(XML_Parser parser, XML_Content *model) -{ - FREE(model); -} - -void * XMLCALL -XML_MemMalloc(XML_Parser parser, size_t size) -{ - return MALLOC(size); -} - -void * XMLCALL -XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) -{ - return REALLOC(ptr, size); -} - -void XMLCALL -XML_MemFree(XML_Parser parser, void *ptr) -{ - FREE(ptr); -} - -void XMLCALL -XML_DefaultCurrent(XML_Parser parser) -{ - if (defaultHandler) { - if (openInternalEntities) - reportDefault(parser, - internalEncoding, - openInternalEntities->internalEventPtr, - openInternalEntities->internalEventEndPtr); - else - reportDefault(parser, encoding, eventPtr, eventEndPtr); - } -} - -const XML_LChar * XMLCALL -XML_ErrorString(enum XML_Error code) -{ - static const XML_LChar* const message[] = { - 0, - XML_L("out of memory"), - XML_L("syntax error"), - XML_L("no element found"), - XML_L("not well-formed (invalid token)"), - XML_L("unclosed token"), - XML_L("partial character"), - XML_L("mismatched tag"), - XML_L("duplicate attribute"), - XML_L("junk after document element"), - XML_L("illegal parameter entity reference"), - XML_L("undefined entity"), - XML_L("recursive entity reference"), - XML_L("asynchronous entity"), - XML_L("reference to invalid character number"), - XML_L("reference to binary entity"), - XML_L("reference to external entity in attribute"), - XML_L("XML or text declaration not at start of entity"), - XML_L("unknown encoding"), - XML_L("encoding specified in XML declaration is incorrect"), - XML_L("unclosed CDATA section"), - XML_L("error in processing external entity reference"), - XML_L("document is not standalone"), - XML_L("unexpected parser state - please send a bug report"), - XML_L("entity declared in parameter entity"), - XML_L("requested feature requires XML_DTD support in Expat"), - XML_L("cannot change setting once parsing has begun"), - XML_L("unbound prefix"), - XML_L("must not undeclare prefix"), - XML_L("incomplete markup in parameter entity"), - XML_L("XML declaration not well-formed"), - XML_L("text declaration not well-formed"), - XML_L("illegal character(s) in public id"), - XML_L("parser suspended"), - XML_L("parser not suspended"), - XML_L("parsing aborted"), - XML_L("parsing finished"), - XML_L("cannot suspend in external parameter entity"), - XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"), - XML_L("reserved prefix (xmlns) must not be declared or undeclared"), - XML_L("prefix must not be bound to one of the reserved namespace names") - }; - if (code > 0 && code < sizeof(message)/sizeof(message[0])) - return message[code]; - return NULL; -} - -const XML_LChar * XMLCALL -XML_ExpatVersion(void) { - - /* V1 is used to string-ize the version number. However, it would - string-ize the actual version macro *names* unless we get them - substituted before being passed to V1. CPP is defined to expand - a macro, then rescan for more expansions. Thus, we use V2 to expand - the version macros, then CPP will expand the resulting V1() macro - with the correct numerals. */ - /* ### I'm assuming cpp is portable in this respect... */ - -#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c) -#define V2(a,b,c) XML_L("expat_")V1(a,b,c) - - return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION); - -#undef V1 -#undef V2 -} - -XML_Expat_Version XMLCALL -XML_ExpatVersionInfo(void) -{ - XML_Expat_Version version; - - version.major = XML_MAJOR_VERSION; - version.minor = XML_MINOR_VERSION; - version.micro = XML_MICRO_VERSION; - - return version; -} - -const XML_Feature * XMLCALL -XML_GetFeatureList(void) -{ - static const XML_Feature features[] = { - {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"), - sizeof(XML_Char)}, - {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"), - sizeof(XML_LChar)}, -#ifdef XML_UNICODE - {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0}, -#endif -#ifdef XML_UNICODE_WCHAR_T - {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0}, -#endif -#ifdef XML_DTD - {XML_FEATURE_DTD, XML_L("XML_DTD"), 0}, -#endif -#ifdef XML_CONTEXT_BYTES - {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"), - XML_CONTEXT_BYTES}, -#endif -#ifdef XML_MIN_SIZE - {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0}, -#endif -#ifdef XML_NS - {XML_FEATURE_NS, XML_L("XML_NS"), 0}, -#endif -#ifdef XML_LARGE_SIZE - {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0}, -#endif -#ifdef XML_ATTR_INFO - {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0}, -#endif - {XML_FEATURE_END, NULL, 0} - }; - - return features; -} - -/* Initially tag->rawName always points into the parse buffer; - for those TAG instances opened while the current parse buffer was - processed, and not yet closed, we need to store tag->rawName in a more - permanent location, since the parse buffer is about to be discarded. -*/ -static XML_Bool -storeRawNames(XML_Parser parser) -{ - TAG *tag = tagStack; - while (tag) { - int bufSize; - int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1); - char *rawNameBuf = tag->buf + nameLen; - /* Stop if already stored. Since tagStack is a stack, we can stop - at the first entry that has already been copied; everything - below it in the stack is already been accounted for in a - previous call to this function. - */ - if (tag->rawName == rawNameBuf) - break; - /* For re-use purposes we need to ensure that the - size of tag->buf is a multiple of sizeof(XML_Char). - */ - bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)); - if (bufSize > tag->bufEnd - tag->buf) { - char *temp = (char *)REALLOC(tag->buf, bufSize); - if (temp == NULL) - return XML_FALSE; - /* if tag->name.str points to tag->buf (only when namespace - processing is off) then we have to update it - */ - if (tag->name.str == (XML_Char *)tag->buf) - tag->name.str = (XML_Char *)temp; - /* if tag->name.localPart is set (when namespace processing is on) - then update it as well, since it will always point into tag->buf - */ - if (tag->name.localPart) - tag->name.localPart = (XML_Char *)temp + (tag->name.localPart - - (XML_Char *)tag->buf); - tag->buf = temp; - tag->bufEnd = temp + bufSize; - rawNameBuf = temp + nameLen; - } - memcpy(rawNameBuf, tag->rawName, tag->rawNameLength); - tag->rawName = rawNameBuf; - tag = tag->parent; - } - return XML_TRUE; -} - -static enum XML_Error PTRCALL -contentProcessor(XML_Parser parser, - const char *start, - const char *end, - const char **endPtr) -{ - enum XML_Error result = doContent(parser, 0, encoding, start, end, - endPtr, (XML_Bool)!ps_finalBuffer); - if (result == XML_ERROR_NONE) { - if (!storeRawNames(parser)) - return XML_ERROR_NO_MEMORY; - } - return result; -} - -static enum XML_Error PTRCALL -externalEntityInitProcessor(XML_Parser parser, - const char *start, - const char *end, - const char **endPtr) -{ - enum XML_Error result = initializeEncoding(parser); - if (result != XML_ERROR_NONE) - return result; - processor = externalEntityInitProcessor2; - return externalEntityInitProcessor2(parser, start, end, endPtr); -} - -static enum XML_Error PTRCALL -externalEntityInitProcessor2(XML_Parser parser, - const char *start, - const char *end, - const char **endPtr) -{ - const char *next = start; /* XmlContentTok doesn't always set the last arg */ - int tok = XmlContentTok(encoding, start, end, &next); - switch (tok) { - case XML_TOK_BOM: - /* If we are at the end of the buffer, this would cause the next stage, - i.e. externalEntityInitProcessor3, to pass control directly to - doContent (by detecting XML_TOK_NONE) without processing any xml text - declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent. - */ - if (next == end && !ps_finalBuffer) { - *endPtr = next; - return XML_ERROR_NONE; - } - start = next; - break; - case XML_TOK_PARTIAL: - if (!ps_finalBuffer) { - *endPtr = start; - return XML_ERROR_NONE; - } - eventPtr = start; - return XML_ERROR_UNCLOSED_TOKEN; - case XML_TOK_PARTIAL_CHAR: - if (!ps_finalBuffer) { - *endPtr = start; - return XML_ERROR_NONE; - } - eventPtr = start; - return XML_ERROR_PARTIAL_CHAR; - } - processor = externalEntityInitProcessor3; - return externalEntityInitProcessor3(parser, start, end, endPtr); -} - -static enum XML_Error PTRCALL -externalEntityInitProcessor3(XML_Parser parser, - const char *start, - const char *end, - const char **endPtr) -{ - int tok; - const char *next = start; /* XmlContentTok doesn't always set the last arg */ - eventPtr = start; - tok = XmlContentTok(encoding, start, end, &next); - eventEndPtr = next; - - switch (tok) { - case XML_TOK_XML_DECL: - { - enum XML_Error result; - result = processXmlDecl(parser, 1, start, next); - if (result != XML_ERROR_NONE) - return result; - switch (ps_parsing) { - case XML_SUSPENDED: - *endPtr = next; - return XML_ERROR_NONE; - case XML_FINISHED: - return XML_ERROR_ABORTED; - default: - start = next; - } - } - break; - case XML_TOK_PARTIAL: - if (!ps_finalBuffer) { - *endPtr = start; - return XML_ERROR_NONE; - } - return XML_ERROR_UNCLOSED_TOKEN; - case XML_TOK_PARTIAL_CHAR: - if (!ps_finalBuffer) { - *endPtr = start; - return XML_ERROR_NONE; - } - return XML_ERROR_PARTIAL_CHAR; - } - processor = externalEntityContentProcessor; - tagLevel = 1; - return externalEntityContentProcessor(parser, start, end, endPtr); -} - -static enum XML_Error PTRCALL -externalEntityContentProcessor(XML_Parser parser, - const char *start, - const char *end, - const char **endPtr) -{ - enum XML_Error result = doContent(parser, 1, encoding, start, end, - endPtr, (XML_Bool)!ps_finalBuffer); - if (result == XML_ERROR_NONE) { - if (!storeRawNames(parser)) - return XML_ERROR_NO_MEMORY; - } - return result; -} - -static enum XML_Error -doContent(XML_Parser parser, - int startTagLevel, - const ENCODING *enc, - const char *s, - const char *end, - const char **nextPtr, - XML_Bool haveMore) -{ - /* save one level of indirection */ - DTD * const dtd = _dtd; - - const char **eventPP; - const char **eventEndPP; - if (enc == encoding) { - eventPP = &eventPtr; - eventEndPP = &eventEndPtr; - } - else { - eventPP = &(openInternalEntities->internalEventPtr); - eventEndPP = &(openInternalEntities->internalEventEndPtr); - } - *eventPP = s; - - for (;;) { - const char *next = s; /* XmlContentTok doesn't always set the last arg */ - int tok = XmlContentTok(enc, s, end, &next); - *eventEndPP = next; - switch (tok) { - case XML_TOK_TRAILING_CR: - if (haveMore) { - *nextPtr = s; - return XML_ERROR_NONE; - } - *eventEndPP = end; - if (characterDataHandler) { - XML_Char c = 0xA; - characterDataHandler(handlerArg, &c, 1); - } - else if (defaultHandler) - reportDefault(parser, enc, s, end); - /* We are at the end of the final buffer, should we check for - XML_SUSPENDED, XML_FINISHED? - */ - if (startTagLevel == 0) - return XML_ERROR_NO_ELEMENTS; - if (tagLevel != startTagLevel) - return XML_ERROR_ASYNC_ENTITY; - *nextPtr = end; - return XML_ERROR_NONE; - case XML_TOK_NONE: - if (haveMore) { - *nextPtr = s; - return XML_ERROR_NONE; - } - if (startTagLevel > 0) { - if (tagLevel != startTagLevel) - return XML_ERROR_ASYNC_ENTITY; - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_NO_ELEMENTS; - case XML_TOK_INVALID: - *eventPP = next; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL: - if (haveMore) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_UNCLOSED_TOKEN; - case XML_TOK_PARTIAL_CHAR: - if (haveMore) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_PARTIAL_CHAR; - case XML_TOK_ENTITY_REF: - { - const XML_Char *name; - ENTITY *entity; - XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (ch) { - if (characterDataHandler) - characterDataHandler(handlerArg, &ch, 1); - else if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - } - name = poolStoreString(&dtd->pool, enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!name) - return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); - poolDiscard(&dtd->pool); - /* First, determine if a check for an existing declaration is needed; - if yes, check that the entity exists, and that it is internal, - otherwise call the skipped entity or default handler. - */ - if (!dtd->hasParamEntityRefs || dtd->standalone) { - if (!entity) - return XML_ERROR_UNDEFINED_ENTITY; - else if (!entity->is_internal) - return XML_ERROR_ENTITY_DECLARED_IN_PE; - } - else if (!entity) { - if (skippedEntityHandler) - skippedEntityHandler(handlerArg, name, 0); - else if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - } - if (entity->open) - return XML_ERROR_RECURSIVE_ENTITY_REF; - if (entity->notation) - return XML_ERROR_BINARY_ENTITY_REF; - if (entity->textPtr) { - enum XML_Error result; - if (!defaultExpandInternalEntities) { - if (skippedEntityHandler) - skippedEntityHandler(handlerArg, entity->name, 0); - else if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - } - result = processInternalEntity(parser, entity, XML_FALSE); - if (result != XML_ERROR_NONE) - return result; - } - else if (externalEntityRefHandler) { - const XML_Char *context; - entity->open = XML_TRUE; - context = getContext(parser); - entity->open = XML_FALSE; - if (!context) - return XML_ERROR_NO_MEMORY; - if (!externalEntityRefHandler(externalEntityRefHandlerArg, - context, - entity->base, - entity->systemId, - entity->publicId)) - return XML_ERROR_EXTERNAL_ENTITY_HANDLING; - poolDiscard(&tempPool); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - } - case XML_TOK_START_TAG_NO_ATTS: - /* fall through */ - case XML_TOK_START_TAG_WITH_ATTS: - { - TAG *tag; - enum XML_Error result; - XML_Char *toPtr; - if (freeTagList) { - tag = freeTagList; - freeTagList = freeTagList->parent; - } - else { - tag = (TAG *)MALLOC(sizeof(TAG)); - if (!tag) - return XML_ERROR_NO_MEMORY; - tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE); - if (!tag->buf) { - FREE(tag); - return XML_ERROR_NO_MEMORY; - } - tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE; - } - tag->bindings = NULL; - tag->parent = tagStack; - tagStack = tag; - tag->name.localPart = NULL; - tag->name.prefix = NULL; - tag->rawName = s + enc->minBytesPerChar; - tag->rawNameLength = XmlNameLength(enc, tag->rawName); - ++tagLevel; - { - const char *rawNameEnd = tag->rawName + tag->rawNameLength; - const char *fromPtr = tag->rawName; - toPtr = (XML_Char *)tag->buf; - for (;;) { - int bufSize; - int convLen; - XmlConvert(enc, - &fromPtr, rawNameEnd, - (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1); - convLen = (int)(toPtr - (XML_Char *)tag->buf); - if (fromPtr == rawNameEnd) { - tag->name.strLen = convLen; - break; - } - bufSize = (int)(tag->bufEnd - tag->buf) << 1; - { - char *temp = (char *)REALLOC(tag->buf, bufSize); - if (temp == NULL) - return XML_ERROR_NO_MEMORY; - tag->buf = temp; - tag->bufEnd = temp + bufSize; - toPtr = (XML_Char *)temp + convLen; - } - } - } - tag->name.str = (XML_Char *)tag->buf; - *toPtr = XML_T('\0'); - result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings)); - if (result) - return result; - if (startElementHandler) - startElementHandler(handlerArg, tag->name.str, - (const XML_Char **)atts); - else if (defaultHandler) - reportDefault(parser, enc, s, next); - poolClear(&tempPool); - break; - } - case XML_TOK_EMPTY_ELEMENT_NO_ATTS: - /* fall through */ - case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: - { - const char *rawName = s + enc->minBytesPerChar; - enum XML_Error result; - BINDING *bindings = NULL; - XML_Bool noElmHandlers = XML_TRUE; - TAG_NAME name; - name.str = poolStoreString(&tempPool, enc, rawName, - rawName + XmlNameLength(enc, rawName)); - if (!name.str) - return XML_ERROR_NO_MEMORY; - poolFinish(&tempPool); - result = storeAtts(parser, enc, s, &name, &bindings); - if (result) - return result; - poolFinish(&tempPool); - if (startElementHandler) { - startElementHandler(handlerArg, name.str, (const XML_Char **)atts); - noElmHandlers = XML_FALSE; - } - if (endElementHandler) { - if (startElementHandler) - *eventPP = *eventEndPP; - endElementHandler(handlerArg, name.str); - noElmHandlers = XML_FALSE; - } - if (noElmHandlers && defaultHandler) - reportDefault(parser, enc, s, next); - poolClear(&tempPool); - while (bindings) { - BINDING *b = bindings; - if (endNamespaceDeclHandler) - endNamespaceDeclHandler(handlerArg, b->prefix->name); - bindings = bindings->nextTagBinding; - b->nextTagBinding = freeBindingList; - freeBindingList = b; - b->prefix->binding = b->prevPrefixBinding; - } - } - if (tagLevel == 0) - return epilogProcessor(parser, next, end, nextPtr); - break; - case XML_TOK_END_TAG: - if (tagLevel == startTagLevel) - return XML_ERROR_ASYNC_ENTITY; - else { - int len; - const char *rawName; - TAG *tag = tagStack; - tagStack = tag->parent; - tag->parent = freeTagList; - freeTagList = tag; - rawName = s + enc->minBytesPerChar*2; - len = XmlNameLength(enc, rawName); - if (len != tag->rawNameLength - || memcmp(tag->rawName, rawName, len) != 0) { - *eventPP = rawName; - return XML_ERROR_TAG_MISMATCH; - } - --tagLevel; - if (endElementHandler) { - const XML_Char *localPart; - const XML_Char *prefix; - XML_Char *uri; - localPart = tag->name.localPart; - if (ns && localPart) { - /* localPart and prefix may have been overwritten in - tag->name.str, since this points to the binding->uri - buffer which gets re-used; so we have to add them again - */ - uri = (XML_Char *)tag->name.str + tag->name.uriLen; - /* don't need to check for space - already done in storeAtts() */ - while (*localPart) *uri++ = *localPart++; - prefix = (XML_Char *)tag->name.prefix; - if (ns_triplets && prefix) { - *uri++ = namespaceSeparator; - while (*prefix) *uri++ = *prefix++; - } - *uri = XML_T('\0'); - } - endElementHandler(handlerArg, tag->name.str); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - while (tag->bindings) { - BINDING *b = tag->bindings; - if (endNamespaceDeclHandler) - endNamespaceDeclHandler(handlerArg, b->prefix->name); - tag->bindings = tag->bindings->nextTagBinding; - b->nextTagBinding = freeBindingList; - freeBindingList = b; - b->prefix->binding = b->prevPrefixBinding; - } - if (tagLevel == 0) - return epilogProcessor(parser, next, end, nextPtr); - } - break; - case XML_TOK_CHAR_REF: - { - int n = XmlCharRefNumber(enc, s); - if (n < 0) - return XML_ERROR_BAD_CHAR_REF; - if (characterDataHandler) { - XML_Char buf[XML_ENCODE_MAX]; - characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf)); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - } - break; - case XML_TOK_XML_DECL: - return XML_ERROR_MISPLACED_XML_PI; - case XML_TOK_DATA_NEWLINE: - if (characterDataHandler) { - XML_Char c = 0xA; - characterDataHandler(handlerArg, &c, 1); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - case XML_TOK_CDATA_SECT_OPEN: - { - enum XML_Error result; - if (startCdataSectionHandler) - startCdataSectionHandler(handlerArg); -#if 0 - /* Suppose you doing a transformation on a document that involves - changing only the character data. You set up a defaultHandler - and a characterDataHandler. The defaultHandler simply copies - characters through. The characterDataHandler does the - transformation and writes the characters out escaping them as - necessary. This case will fail to work if we leave out the - following two lines (because & and < inside CDATA sections will - be incorrectly escaped). - - However, now we have a start/endCdataSectionHandler, so it seems - easier to let the user deal with this. - */ - else if (characterDataHandler) - characterDataHandler(handlerArg, dataBuf, 0); -#endif - else if (defaultHandler) - reportDefault(parser, enc, s, next); - result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore); - if (result != XML_ERROR_NONE) - return result; - else if (!next) { - processor = cdataSectionProcessor; - return result; - } - } - break; - case XML_TOK_TRAILING_RSQB: - if (haveMore) { - *nextPtr = s; - return XML_ERROR_NONE; - } - if (characterDataHandler) { - if (MUST_CONVERT(enc, s)) { - ICHAR *dataPtr = (ICHAR *)dataBuf; - XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); - characterDataHandler(handlerArg, dataBuf, - (int)(dataPtr - (ICHAR *)dataBuf)); - } - else - characterDataHandler(handlerArg, - (XML_Char *)s, - (int)((XML_Char *)end - (XML_Char *)s)); - } - else if (defaultHandler) - reportDefault(parser, enc, s, end); - /* We are at the end of the final buffer, should we check for - XML_SUSPENDED, XML_FINISHED? - */ - if (startTagLevel == 0) { - *eventPP = end; - return XML_ERROR_NO_ELEMENTS; - } - if (tagLevel != startTagLevel) { - *eventPP = end; - return XML_ERROR_ASYNC_ENTITY; - } - *nextPtr = end; - return XML_ERROR_NONE; - case XML_TOK_DATA_CHARS: - { - XML_CharacterDataHandler charDataHandler = characterDataHandler; - if (charDataHandler) { - if (MUST_CONVERT(enc, s)) { - for (;;) { - ICHAR *dataPtr = (ICHAR *)dataBuf; - XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); - *eventEndPP = s; - charDataHandler(handlerArg, dataBuf, - (int)(dataPtr - (ICHAR *)dataBuf)); - if (s == next) - break; - *eventPP = s; - } - } - else - charDataHandler(handlerArg, - (XML_Char *)s, - (int)((XML_Char *)next - (XML_Char *)s)); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - } - break; - case XML_TOK_PI: - if (!reportProcessingInstruction(parser, enc, s, next)) - return XML_ERROR_NO_MEMORY; - break; - case XML_TOK_COMMENT: - if (!reportComment(parser, enc, s, next)) - return XML_ERROR_NO_MEMORY; - break; - default: - if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - } - *eventPP = s = next; - switch (ps_parsing) { - case XML_SUSPENDED: - *nextPtr = next; - return XML_ERROR_NONE; - case XML_FINISHED: - return XML_ERROR_ABORTED; - default: ; - } - } - /* not reached */ -} - -/* Precondition: all arguments must be non-NULL; - Purpose: - - normalize attributes - - check attributes for well-formedness - - generate namespace aware attribute names (URI, prefix) - - build list of attributes for startElementHandler - - default attributes - - process namespace declarations (check and report them) - - generate namespace aware element name (URI, prefix) -*/ -static enum XML_Error -storeAtts(XML_Parser parser, const ENCODING *enc, - const char *attStr, TAG_NAME *tagNamePtr, - BINDING **bindingsPtr) -{ - DTD * const dtd = _dtd; /* save one level of indirection */ - ELEMENT_TYPE *elementType; - int nDefaultAtts; - const XML_Char **appAtts; /* the attribute list for the application */ - int attIndex = 0; - int prefixLen; - int i; - int n; - XML_Char *uri; - int nPrefixes = 0; - BINDING *binding; - const XML_Char *localPart; - - /* lookup the element type name */ - elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0); - if (!elementType) { - const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); - if (!name) - return XML_ERROR_NO_MEMORY; - elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name, - sizeof(ELEMENT_TYPE)); - if (!elementType) - return XML_ERROR_NO_MEMORY; - if (ns && !setElementTypePrefix(parser, elementType)) - return XML_ERROR_NO_MEMORY; - } - nDefaultAtts = elementType->nDefaultAtts; - - /* get the attributes from the tokenizer */ - n = XmlGetAttributes(enc, attStr, attsSize, atts); - if (n + nDefaultAtts > attsSize) { - int oldAttsSize = attsSize; - ATTRIBUTE *temp; -#ifdef XML_ATTR_INFO - XML_AttrInfo *temp2; -#endif - attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; - temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE)); - if (temp == NULL) - return XML_ERROR_NO_MEMORY; - atts = temp; -#ifdef XML_ATTR_INFO - temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo)); - if (temp2 == NULL) - return XML_ERROR_NO_MEMORY; - attInfo = temp2; -#endif - if (n > oldAttsSize) - XmlGetAttributes(enc, attStr, n, atts); - } - - appAtts = (const XML_Char **)atts; - for (i = 0; i < n; i++) { - ATTRIBUTE *currAtt = &atts[i]; -#ifdef XML_ATTR_INFO - XML_AttrInfo *currAttInfo = &attInfo[i]; -#endif - /* add the name and value to the attribute list */ - ATTRIBUTE_ID *attId = getAttributeId(parser, enc, currAtt->name, - currAtt->name - + XmlNameLength(enc, currAtt->name)); - if (!attId) - return XML_ERROR_NO_MEMORY; -#ifdef XML_ATTR_INFO - currAttInfo->nameStart = parseEndByteIndex - (parseEndPtr - currAtt->name); - currAttInfo->nameEnd = currAttInfo->nameStart + - XmlNameLength(enc, currAtt->name); - currAttInfo->valueStart = parseEndByteIndex - - (parseEndPtr - currAtt->valuePtr); - currAttInfo->valueEnd = parseEndByteIndex - (parseEndPtr - currAtt->valueEnd); -#endif - /* Detect duplicate attributes by their QNames. This does not work when - namespace processing is turned on and different prefixes for the same - namespace are used. For this case we have a check further down. - */ - if ((attId->name)[-1]) { - if (enc == encoding) - eventPtr = atts[i].name; - return XML_ERROR_DUPLICATE_ATTRIBUTE; - } - (attId->name)[-1] = 1; - appAtts[attIndex++] = attId->name; - if (!atts[i].normalized) { - enum XML_Error result; - XML_Bool isCdata = XML_TRUE; - - /* figure out whether declared as other than CDATA */ - if (attId->maybeTokenized) { - int j; - for (j = 0; j < nDefaultAtts; j++) { - if (attId == elementType->defaultAtts[j].id) { - isCdata = elementType->defaultAtts[j].isCdata; - break; - } - } - } - - /* normalize the attribute value */ - result = storeAttributeValue(parser, enc, isCdata, - atts[i].valuePtr, atts[i].valueEnd, - &tempPool); - if (result) - return result; - appAtts[attIndex] = poolStart(&tempPool); - poolFinish(&tempPool); - } - else { - /* the value did not need normalizing */ - appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr, - atts[i].valueEnd); - if (appAtts[attIndex] == 0) - return XML_ERROR_NO_MEMORY; - poolFinish(&tempPool); - } - /* handle prefixed attribute names */ - if (attId->prefix) { - if (attId->xmlns) { - /* deal with namespace declarations here */ - enum XML_Error result = addBinding(parser, attId->prefix, attId, - appAtts[attIndex], bindingsPtr); - if (result) - return result; - --attIndex; - } - else { - /* deal with other prefixed names later */ - attIndex++; - nPrefixes++; - (attId->name)[-1] = 2; - } - } - else - attIndex++; - } - - /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */ - nSpecifiedAtts = attIndex; - if (elementType->idAtt && (elementType->idAtt->name)[-1]) { - for (i = 0; i < attIndex; i += 2) - if (appAtts[i] == elementType->idAtt->name) { - idAttIndex = i; - break; - } - } - else - idAttIndex = -1; - - /* do attribute defaulting */ - for (i = 0; i < nDefaultAtts; i++) { - const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i; - if (!(da->id->name)[-1] && da->value) { - if (da->id->prefix) { - if (da->id->xmlns) { - enum XML_Error result = addBinding(parser, da->id->prefix, da->id, - da->value, bindingsPtr); - if (result) - return result; - } - else { - (da->id->name)[-1] = 2; - nPrefixes++; - appAtts[attIndex++] = da->id->name; - appAtts[attIndex++] = da->value; - } - } - else { - (da->id->name)[-1] = 1; - appAtts[attIndex++] = da->id->name; - appAtts[attIndex++] = da->value; - } - } - } - appAtts[attIndex] = 0; - - /* expand prefixed attribute names, check for duplicates, - and clear flags that say whether attributes were specified */ - i = 0; - if (nPrefixes) { - int j; /* hash table index */ - unsigned long version = nsAttsVersion; - int nsAttsSize = (int)1 << nsAttsPower; - /* size of hash table must be at least 2 * (# of prefixed attributes) */ - if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */ - NS_ATT *temp; - /* hash table size must also be a power of 2 and >= 8 */ - while (nPrefixes >> nsAttsPower++); - if (nsAttsPower < 3) - nsAttsPower = 3; - nsAttsSize = (int)1 << nsAttsPower; - temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT)); - if (!temp) - return XML_ERROR_NO_MEMORY; - nsAtts = temp; - version = 0; /* force re-initialization of nsAtts hash table */ - } - /* using a version flag saves us from initializing nsAtts every time */ - if (!version) { /* initialize version flags when version wraps around */ - version = INIT_ATTS_VERSION; - for (j = nsAttsSize; j != 0; ) - nsAtts[--j].version = version; - } - nsAttsVersion = --version; - - /* expand prefixed names and check for duplicates */ - for (; i < attIndex; i += 2) { - const XML_Char *s = appAtts[i]; - if (s[-1] == 2) { /* prefixed */ - ATTRIBUTE_ID *id; - const BINDING *b; - unsigned long uriHash = hash_secret_salt; - ((XML_Char *)s)[-1] = 0; /* clear flag */ - id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0); - b = id->prefix->binding; - if (!b) - return XML_ERROR_UNBOUND_PREFIX; - - /* as we expand the name we also calculate its hash value */ - for (j = 0; j < b->uriLen; j++) { - const XML_Char c = b->uri[j]; - if (!poolAppendChar(&tempPool, c)) - return XML_ERROR_NO_MEMORY; - uriHash = CHAR_HASH(uriHash, c); - } - while (*s++ != XML_T(ASCII_COLON)) - ; - do { /* copies null terminator */ - const XML_Char c = *s; - if (!poolAppendChar(&tempPool, *s)) - return XML_ERROR_NO_MEMORY; - uriHash = CHAR_HASH(uriHash, c); - } while (*s++); - - { /* Check hash table for duplicate of expanded name (uriName). - Derived from code in lookup(parser, HASH_TABLE *table, ...). - */ - unsigned char step = 0; - unsigned long mask = nsAttsSize - 1; - j = uriHash & mask; /* index into hash table */ - while (nsAtts[j].version == version) { - /* for speed we compare stored hash values first */ - if (uriHash == nsAtts[j].hash) { - const XML_Char *s1 = poolStart(&tempPool); - const XML_Char *s2 = nsAtts[j].uriName; - /* s1 is null terminated, but not s2 */ - for (; *s1 == *s2 && *s1 != 0; s1++, s2++); - if (*s1 == 0) - return XML_ERROR_DUPLICATE_ATTRIBUTE; - } - if (!step) - step = PROBE_STEP(uriHash, mask, nsAttsPower); - j < step ? (j += nsAttsSize - step) : (j -= step); - } - } - - if (ns_triplets) { /* append namespace separator and prefix */ - tempPool.ptr[-1] = namespaceSeparator; - s = b->prefix->name; - do { - if (!poolAppendChar(&tempPool, *s)) - return XML_ERROR_NO_MEMORY; - } while (*s++); - } - - /* store expanded name in attribute list */ - s = poolStart(&tempPool); - poolFinish(&tempPool); - appAtts[i] = s; - - /* fill empty slot with new version, uriName and hash value */ - nsAtts[j].version = version; - nsAtts[j].hash = uriHash; - nsAtts[j].uriName = s; - - if (!--nPrefixes) { - i += 2; - break; - } - } - else /* not prefixed */ - ((XML_Char *)s)[-1] = 0; /* clear flag */ - } - } - /* clear flags for the remaining attributes */ - for (; i < attIndex; i += 2) - ((XML_Char *)(appAtts[i]))[-1] = 0; - for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding) - binding->attId->name[-1] = 0; - - if (!ns) - return XML_ERROR_NONE; - - /* expand the element type name */ - if (elementType->prefix) { - binding = elementType->prefix->binding; - if (!binding) - return XML_ERROR_UNBOUND_PREFIX; - localPart = tagNamePtr->str; - while (*localPart++ != XML_T(ASCII_COLON)) - ; - } - else if (dtd->defaultPrefix.binding) { - binding = dtd->defaultPrefix.binding; - localPart = tagNamePtr->str; - } - else - return XML_ERROR_NONE; - prefixLen = 0; - if (ns_triplets && binding->prefix->name) { - for (; binding->prefix->name[prefixLen++];) - ; /* prefixLen includes null terminator */ - } - tagNamePtr->localPart = localPart; - tagNamePtr->uriLen = binding->uriLen; - tagNamePtr->prefix = binding->prefix->name; - tagNamePtr->prefixLen = prefixLen; - for (i = 0; localPart[i++];) - ; /* i includes null terminator */ - n = i + binding->uriLen + prefixLen; - if (n > binding->uriAlloc) { - TAG *p; - uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char)); - if (!uri) - return XML_ERROR_NO_MEMORY; - binding->uriAlloc = n + EXPAND_SPARE; - memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char)); - for (p = tagStack; p; p = p->parent) - if (p->name.str == binding->uri) - p->name.str = uri; - FREE(binding->uri); - binding->uri = uri; - } - /* if namespaceSeparator != '\0' then uri includes it already */ - uri = binding->uri + binding->uriLen; - memcpy(uri, localPart, i * sizeof(XML_Char)); - /* we always have a namespace separator between localPart and prefix */ - if (prefixLen) { - uri += i - 1; - *uri = namespaceSeparator; /* replace null terminator */ - memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char)); - } - tagNamePtr->str = binding->uri; - return XML_ERROR_NONE; -} - -/* addBinding() overwrites the value of prefix->binding without checking. - Therefore one must keep track of the old value outside of addBinding(). -*/ -static enum XML_Error -addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, - const XML_Char *uri, BINDING **bindingsPtr) -{ - static const XML_Char xmlNamespace[] = { - ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH, - ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, - ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, - ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8, ASCII_SLASH, - ASCII_n, ASCII_a, ASCII_m, ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c, - ASCII_e, '\0' - }; - static const int xmlLen = - (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1; - static const XML_Char xmlnsNamespace[] = { - ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH, - ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, - ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_2, ASCII_0, ASCII_0, - ASCII_0, ASCII_SLASH, ASCII_x, ASCII_m, ASCII_l, ASCII_n, ASCII_s, - ASCII_SLASH, '\0' - }; - static const int xmlnsLen = - (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1; - - XML_Bool mustBeXML = XML_FALSE; - XML_Bool isXML = XML_TRUE; - XML_Bool isXMLNS = XML_TRUE; - - BINDING *b; - int len; - - /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */ - if (*uri == XML_T('\0') && prefix->name) - return XML_ERROR_UNDECLARING_PREFIX; - - if (prefix->name - && prefix->name[0] == XML_T(ASCII_x) - && prefix->name[1] == XML_T(ASCII_m) - && prefix->name[2] == XML_T(ASCII_l)) { - - /* Not allowed to bind xmlns */ - if (prefix->name[3] == XML_T(ASCII_n) - && prefix->name[4] == XML_T(ASCII_s) - && prefix->name[5] == XML_T('\0')) - return XML_ERROR_RESERVED_PREFIX_XMLNS; - - if (prefix->name[3] == XML_T('\0')) - mustBeXML = XML_TRUE; - } - - for (len = 0; uri[len]; len++) { - if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len])) - isXML = XML_FALSE; - - if (!mustBeXML && isXMLNS - && (len > xmlnsLen || uri[len] != xmlnsNamespace[len])) - isXMLNS = XML_FALSE; - } - isXML = isXML && len == xmlLen; - isXMLNS = isXMLNS && len == xmlnsLen; - - if (mustBeXML != isXML) - return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML - : XML_ERROR_RESERVED_NAMESPACE_URI; - - if (isXMLNS) - return XML_ERROR_RESERVED_NAMESPACE_URI; - - if (namespaceSeparator) - len++; - if (freeBindingList) { - b = freeBindingList; - if (len > b->uriAlloc) { - XML_Char *temp = (XML_Char *)REALLOC(b->uri, - sizeof(XML_Char) * (len + EXPAND_SPARE)); - if (temp == NULL) - return XML_ERROR_NO_MEMORY; - b->uri = temp; - b->uriAlloc = len + EXPAND_SPARE; - } - freeBindingList = b->nextTagBinding; - } - else { - b = (BINDING *)MALLOC(sizeof(BINDING)); - if (!b) - return XML_ERROR_NO_MEMORY; - b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE)); - if (!b->uri) { - FREE(b); - return XML_ERROR_NO_MEMORY; - } - b->uriAlloc = len + EXPAND_SPARE; - } - b->uriLen = len; - memcpy(b->uri, uri, len * sizeof(XML_Char)); - if (namespaceSeparator) - b->uri[len - 1] = namespaceSeparator; - b->prefix = prefix; - b->attId = attId; - b->prevPrefixBinding = prefix->binding; - /* NULL binding when default namespace undeclared */ - if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix) - prefix->binding = NULL; - else - prefix->binding = b; - b->nextTagBinding = *bindingsPtr; - *bindingsPtr = b; - /* if attId == NULL then we are not starting a namespace scope */ - if (attId && startNamespaceDeclHandler) - startNamespaceDeclHandler(handlerArg, prefix->name, - prefix->binding ? uri : 0); - return XML_ERROR_NONE; -} - -/* The idea here is to avoid using stack for each CDATA section when - the whole file is parsed with one call. -*/ -static enum XML_Error PTRCALL -cdataSectionProcessor(XML_Parser parser, - const char *start, - const char *end, - const char **endPtr) -{ - enum XML_Error result = doCdataSection(parser, encoding, &start, end, - endPtr, (XML_Bool)!ps_finalBuffer); - if (result != XML_ERROR_NONE) - return result; - if (start) { - if (parentParser) { /* we are parsing an external entity */ - processor = externalEntityContentProcessor; - return externalEntityContentProcessor(parser, start, end, endPtr); - } - else { - processor = contentProcessor; - return contentProcessor(parser, start, end, endPtr); - } - } - return result; -} - -/* startPtr gets set to non-null if the section is closed, and to null if - the section is not yet closed. -*/ -static enum XML_Error -doCdataSection(XML_Parser parser, - const ENCODING *enc, - const char **startPtr, - const char *end, - const char **nextPtr, - XML_Bool haveMore) -{ - const char *s = *startPtr; - const char **eventPP; - const char **eventEndPP; - if (enc == encoding) { - eventPP = &eventPtr; - *eventPP = s; - eventEndPP = &eventEndPtr; - } - else { - eventPP = &(openInternalEntities->internalEventPtr); - eventEndPP = &(openInternalEntities->internalEventEndPtr); - } - *eventPP = s; - *startPtr = NULL; - - for (;;) { - const char *next; - int tok = XmlCdataSectionTok(enc, s, end, &next); - *eventEndPP = next; - switch (tok) { - case XML_TOK_CDATA_SECT_CLOSE: - if (endCdataSectionHandler) - endCdataSectionHandler(handlerArg); -#if 0 - /* see comment under XML_TOK_CDATA_SECT_OPEN */ - else if (characterDataHandler) - characterDataHandler(handlerArg, dataBuf, 0); -#endif - else if (defaultHandler) - reportDefault(parser, enc, s, next); - *startPtr = next; - *nextPtr = next; - if (ps_parsing == XML_FINISHED) - return XML_ERROR_ABORTED; - else - return XML_ERROR_NONE; - case XML_TOK_DATA_NEWLINE: - if (characterDataHandler) { - XML_Char c = 0xA; - characterDataHandler(handlerArg, &c, 1); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - break; - case XML_TOK_DATA_CHARS: - { - XML_CharacterDataHandler charDataHandler = characterDataHandler; - if (charDataHandler) { - if (MUST_CONVERT(enc, s)) { - for (;;) { - ICHAR *dataPtr = (ICHAR *)dataBuf; - XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); - *eventEndPP = next; - charDataHandler(handlerArg, dataBuf, - (int)(dataPtr - (ICHAR *)dataBuf)); - if (s == next) - break; - *eventPP = s; - } - } - else - charDataHandler(handlerArg, - (XML_Char *)s, - (int)((XML_Char *)next - (XML_Char *)s)); - } - else if (defaultHandler) - reportDefault(parser, enc, s, next); - } - break; - case XML_TOK_INVALID: - *eventPP = next; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL_CHAR: - if (haveMore) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_PARTIAL_CHAR; - case XML_TOK_PARTIAL: - case XML_TOK_NONE: - if (haveMore) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_UNCLOSED_CDATA_SECTION; - default: - *eventPP = next; - return XML_ERROR_UNEXPECTED_STATE; - } - - *eventPP = s = next; - switch (ps_parsing) { - case XML_SUSPENDED: - *nextPtr = next; - return XML_ERROR_NONE; - case XML_FINISHED: - return XML_ERROR_ABORTED; - default: ; - } - } - /* not reached */ -} - -#ifdef XML_DTD - -/* The idea here is to avoid using stack for each IGNORE section when - the whole file is parsed with one call. -*/ -static enum XML_Error PTRCALL -ignoreSectionProcessor(XML_Parser parser, - const char *start, - const char *end, - const char **endPtr) -{ - enum XML_Error result = doIgnoreSection(parser, encoding, &start, end, - endPtr, (XML_Bool)!ps_finalBuffer); - if (result != XML_ERROR_NONE) - return result; - if (start) { - processor = prologProcessor; - return prologProcessor(parser, start, end, endPtr); - } - return result; -} - -/* startPtr gets set to non-null is the section is closed, and to null - if the section is not yet closed. -*/ -static enum XML_Error -doIgnoreSection(XML_Parser parser, - const ENCODING *enc, - const char **startPtr, - const char *end, - const char **nextPtr, - XML_Bool haveMore) -{ - const char *next; - int tok; - const char *s = *startPtr; - const char **eventPP; - const char **eventEndPP; - if (enc == encoding) { - eventPP = &eventPtr; - *eventPP = s; - eventEndPP = &eventEndPtr; - } - else { - eventPP = &(openInternalEntities->internalEventPtr); - eventEndPP = &(openInternalEntities->internalEventEndPtr); - } - *eventPP = s; - *startPtr = NULL; - tok = XmlIgnoreSectionTok(enc, s, end, &next); - *eventEndPP = next; - switch (tok) { - case XML_TOK_IGNORE_SECT: - if (defaultHandler) - reportDefault(parser, enc, s, next); - *startPtr = next; - *nextPtr = next; - if (ps_parsing == XML_FINISHED) - return XML_ERROR_ABORTED; - else - return XML_ERROR_NONE; - case XML_TOK_INVALID: - *eventPP = next; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL_CHAR: - if (haveMore) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_PARTIAL_CHAR; - case XML_TOK_PARTIAL: - case XML_TOK_NONE: - if (haveMore) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */ - default: - *eventPP = next; - return XML_ERROR_UNEXPECTED_STATE; - } - /* not reached */ -} - -#endif /* XML_DTD */ - -static enum XML_Error -initializeEncoding(XML_Parser parser) -{ - const char *s; -#ifdef XML_UNICODE - char encodingBuf[128]; - if (!protocolEncodingName) - s = NULL; - else { - int i; - for (i = 0; protocolEncodingName[i]; i++) { - if (i == sizeof(encodingBuf) - 1 - || (protocolEncodingName[i] & ~0x7f) != 0) { - encodingBuf[0] = '\0'; - break; - } - encodingBuf[i] = (char)protocolEncodingName[i]; - } - encodingBuf[i] = '\0'; - s = encodingBuf; - } -#else - s = protocolEncodingName; -#endif - if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s)) - return XML_ERROR_NONE; - return handleUnknownEncoding(parser, protocolEncodingName); -} - -static enum XML_Error -processXmlDecl(XML_Parser parser, int isGeneralTextEntity, - const char *s, const char *next) -{ - const char *encodingName = NULL; - const XML_Char *storedEncName = NULL; - const ENCODING *newEncoding = NULL; - const char *version = NULL; - const char *versionend; - const XML_Char *storedversion = NULL; - int standalone = -1; - if (!(ns - ? XmlParseXmlDeclNS - : XmlParseXmlDecl)(isGeneralTextEntity, - encoding, - s, - next, - &eventPtr, - &version, - &versionend, - &encodingName, - &newEncoding, - &standalone)) { - if (isGeneralTextEntity) - return XML_ERROR_TEXT_DECL; - else - return XML_ERROR_XML_DECL; - } - if (!isGeneralTextEntity && standalone == 1) { - _dtd->standalone = XML_TRUE; -#ifdef XML_DTD - if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE) - paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; -#endif /* XML_DTD */ - } - if (xmlDeclHandler) { - if (encodingName != NULL) { - storedEncName = poolStoreString(&temp2Pool, - encoding, - encodingName, - encodingName - + XmlNameLength(encoding, encodingName)); - if (!storedEncName) - return XML_ERROR_NO_MEMORY; - poolFinish(&temp2Pool); - } - if (version) { - storedversion = poolStoreString(&temp2Pool, - encoding, - version, - versionend - encoding->minBytesPerChar); - if (!storedversion) - return XML_ERROR_NO_MEMORY; - } - xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone); - } - else if (defaultHandler) - reportDefault(parser, encoding, s, next); - if (protocolEncodingName == NULL) { - if (newEncoding) { - if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) { - eventPtr = encodingName; - return XML_ERROR_INCORRECT_ENCODING; - } - encoding = newEncoding; - } - else if (encodingName) { - enum XML_Error result; - if (!storedEncName) { - storedEncName = poolStoreString( - &temp2Pool, encoding, encodingName, - encodingName + XmlNameLength(encoding, encodingName)); - if (!storedEncName) - return XML_ERROR_NO_MEMORY; - } - result = handleUnknownEncoding(parser, storedEncName); - poolClear(&temp2Pool); - if (result == XML_ERROR_UNKNOWN_ENCODING) - eventPtr = encodingName; - return result; - } - } - - if (storedEncName || storedversion) - poolClear(&temp2Pool); - - return XML_ERROR_NONE; -} - -static enum XML_Error -handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) -{ - if (unknownEncodingHandler) { - XML_Encoding info; - int i; - for (i = 0; i < 256; i++) - info.map[i] = -1; - info.convert = NULL; - info.data = NULL; - info.release = NULL; - if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName, - &info)) { - ENCODING *enc; - unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding()); - if (!unknownEncodingMem) { - if (info.release) - info.release(info.data); - return XML_ERROR_NO_MEMORY; - } - enc = (ns - ? XmlInitUnknownEncodingNS - : XmlInitUnknownEncoding)(unknownEncodingMem, - info.map, - info.convert, - info.data); - if (enc) { - unknownEncodingData = info.data; - unknownEncodingRelease = info.release; - encoding = enc; - return XML_ERROR_NONE; - } - } - if (info.release != NULL) - info.release(info.data); - } - return XML_ERROR_UNKNOWN_ENCODING; -} - -static enum XML_Error PTRCALL -prologInitProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - enum XML_Error result = initializeEncoding(parser); - if (result != XML_ERROR_NONE) - return result; - processor = prologProcessor; - return prologProcessor(parser, s, end, nextPtr); -} - -#ifdef XML_DTD - -static enum XML_Error PTRCALL -externalParEntInitProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - enum XML_Error result = initializeEncoding(parser); - if (result != XML_ERROR_NONE) - return result; - - /* we know now that XML_Parse(Buffer) has been called, - so we consider the external parameter entity read */ - _dtd->paramEntityRead = XML_TRUE; - - if (prologState.inEntityValue) { - processor = entityValueInitProcessor; - return entityValueInitProcessor(parser, s, end, nextPtr); - } - else { - processor = externalParEntProcessor; - return externalParEntProcessor(parser, s, end, nextPtr); - } -} - -static enum XML_Error PTRCALL -entityValueInitProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - int tok; - const char *start = s; - const char *next = start; - eventPtr = start; - - for (;;) { - tok = XmlPrologTok(encoding, start, end, &next); - eventEndPtr = next; - if (tok <= 0) { - if (!ps_finalBuffer && tok != XML_TOK_INVALID) { - *nextPtr = s; - return XML_ERROR_NONE; - } - switch (tok) { - case XML_TOK_INVALID: - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL: - return XML_ERROR_UNCLOSED_TOKEN; - case XML_TOK_PARTIAL_CHAR: - return XML_ERROR_PARTIAL_CHAR; - case XML_TOK_NONE: /* start == end */ - default: - break; - } - /* found end of entity value - can store it now */ - return storeEntityValue(parser, encoding, s, end); - } - else if (tok == XML_TOK_XML_DECL) { - enum XML_Error result; - result = processXmlDecl(parser, 0, start, next); - if (result != XML_ERROR_NONE) - return result; - switch (ps_parsing) { - case XML_SUSPENDED: - *nextPtr = next; - return XML_ERROR_NONE; - case XML_FINISHED: - return XML_ERROR_ABORTED; - default: - *nextPtr = next; - } - /* stop scanning for text declaration - we found one */ - processor = entityValueProcessor; - return entityValueProcessor(parser, next, end, nextPtr); - } - /* If we are at the end of the buffer, this would cause XmlPrologTok to - return XML_TOK_NONE on the next call, which would then cause the - function to exit with *nextPtr set to s - that is what we want for other - tokens, but not for the BOM - we would rather like to skip it; - then, when this routine is entered the next time, XmlPrologTok will - return XML_TOK_INVALID, since the BOM is still in the buffer - */ - else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) { - *nextPtr = next; - return XML_ERROR_NONE; - } - start = next; - eventPtr = start; - } -} - -static enum XML_Error PTRCALL -externalParEntProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - const char *next = s; - int tok; - - tok = XmlPrologTok(encoding, s, end, &next); - if (tok <= 0) { - if (!ps_finalBuffer && tok != XML_TOK_INVALID) { - *nextPtr = s; - return XML_ERROR_NONE; - } - switch (tok) { - case XML_TOK_INVALID: - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL: - return XML_ERROR_UNCLOSED_TOKEN; - case XML_TOK_PARTIAL_CHAR: - return XML_ERROR_PARTIAL_CHAR; - case XML_TOK_NONE: /* start == end */ - default: - break; - } - } - /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM. - However, when parsing an external subset, doProlog will not accept a BOM - as valid, and report a syntax error, so we have to skip the BOM - */ - else if (tok == XML_TOK_BOM) { - s = next; - tok = XmlPrologTok(encoding, s, end, &next); - } - - processor = prologProcessor; - return doProlog(parser, encoding, s, end, tok, next, - nextPtr, (XML_Bool)!ps_finalBuffer); -} - -static enum XML_Error PTRCALL -entityValueProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - const char *start = s; - const char *next = s; - const ENCODING *enc = encoding; - int tok; - - for (;;) { - tok = XmlPrologTok(enc, start, end, &next); - if (tok <= 0) { - if (!ps_finalBuffer && tok != XML_TOK_INVALID) { - *nextPtr = s; - return XML_ERROR_NONE; - } - switch (tok) { - case XML_TOK_INVALID: - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL: - return XML_ERROR_UNCLOSED_TOKEN; - case XML_TOK_PARTIAL_CHAR: - return XML_ERROR_PARTIAL_CHAR; - case XML_TOK_NONE: /* start == end */ - default: - break; - } - /* found end of entity value - can store it now */ - return storeEntityValue(parser, enc, s, end); - } - start = next; - } -} - -#endif /* XML_DTD */ - -static enum XML_Error PTRCALL -prologProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - const char *next = s; - int tok = XmlPrologTok(encoding, s, end, &next); - return doProlog(parser, encoding, s, end, tok, next, - nextPtr, (XML_Bool)!ps_finalBuffer); -} - -static enum XML_Error -doProlog(XML_Parser parser, - const ENCODING *enc, - const char *s, - const char *end, - int tok, - const char *next, - const char **nextPtr, - XML_Bool haveMore) -{ -#ifdef XML_DTD - static const XML_Char externalSubsetName[] = { ASCII_HASH , '\0' }; -#endif /* XML_DTD */ - static const XML_Char atypeCDATA[] = - { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; - static const XML_Char atypeID[] = { ASCII_I, ASCII_D, '\0' }; - static const XML_Char atypeIDREF[] = - { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' }; - static const XML_Char atypeIDREFS[] = - { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' }; - static const XML_Char atypeENTITY[] = - { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' }; - static const XML_Char atypeENTITIES[] = { ASCII_E, ASCII_N, - ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' }; - static const XML_Char atypeNMTOKEN[] = { - ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' }; - static const XML_Char atypeNMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T, - ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' }; - static const XML_Char notationPrefix[] = { ASCII_N, ASCII_O, ASCII_T, - ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0' }; - static const XML_Char enumValueSep[] = { ASCII_PIPE, '\0' }; - static const XML_Char enumValueStart[] = { ASCII_LPAREN, '\0' }; - - /* save one level of indirection */ - DTD * const dtd = _dtd; - - const char **eventPP; - const char **eventEndPP; - enum XML_Content_Quant quant; - - if (enc == encoding) { - eventPP = &eventPtr; - eventEndPP = &eventEndPtr; - } - else { - eventPP = &(openInternalEntities->internalEventPtr); - eventEndPP = &(openInternalEntities->internalEventEndPtr); - } - - for (;;) { - int role; - XML_Bool handleDefault = XML_TRUE; - *eventPP = s; - *eventEndPP = next; - if (tok <= 0) { - if (haveMore && tok != XML_TOK_INVALID) { - *nextPtr = s; - return XML_ERROR_NONE; - } - switch (tok) { - case XML_TOK_INVALID: - *eventPP = next; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL: - return XML_ERROR_UNCLOSED_TOKEN; - case XML_TOK_PARTIAL_CHAR: - return XML_ERROR_PARTIAL_CHAR; - case -XML_TOK_PROLOG_S: - tok = -tok; - break; - case XML_TOK_NONE: -#ifdef XML_DTD - /* for internal PE NOT referenced between declarations */ - if (enc != encoding && !openInternalEntities->betweenDecl) { - *nextPtr = s; - return XML_ERROR_NONE; - } - /* WFC: PE Between Declarations - must check that PE contains - complete markup, not only for external PEs, but also for - internal PEs if the reference occurs between declarations. - */ - if (isParamEntity || enc != encoding) { - if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc) - == XML_ROLE_ERROR) - return XML_ERROR_INCOMPLETE_PE; - *nextPtr = s; - return XML_ERROR_NONE; - } -#endif /* XML_DTD */ - return XML_ERROR_NO_ELEMENTS; - default: - tok = -tok; - next = end; - break; - } - } - role = XmlTokenRole(&prologState, tok, s, next, enc); - switch (role) { - case XML_ROLE_XML_DECL: - { - enum XML_Error result = processXmlDecl(parser, 0, s, next); - if (result != XML_ERROR_NONE) - return result; - enc = encoding; - handleDefault = XML_FALSE; - } - break; - case XML_ROLE_DOCTYPE_NAME: - if (startDoctypeDeclHandler) { - doctypeName = poolStoreString(&tempPool, enc, s, next); - if (!doctypeName) - return XML_ERROR_NO_MEMORY; - poolFinish(&tempPool); - doctypePubid = NULL; - handleDefault = XML_FALSE; - } - doctypeSysid = NULL; /* always initialize to NULL */ - break; - case XML_ROLE_DOCTYPE_INTERNAL_SUBSET: - if (startDoctypeDeclHandler) { - startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid, - doctypePubid, 1); - doctypeName = NULL; - poolClear(&tempPool); - handleDefault = XML_FALSE; - } - break; -#ifdef XML_DTD - case XML_ROLE_TEXT_DECL: - { - enum XML_Error result = processXmlDecl(parser, 1, s, next); - if (result != XML_ERROR_NONE) - return result; - enc = encoding; - handleDefault = XML_FALSE; - } - break; -#endif /* XML_DTD */ - case XML_ROLE_DOCTYPE_PUBLIC_ID: -#ifdef XML_DTD - useForeignDTD = XML_FALSE; - declEntity = (ENTITY *)lookup(parser, - &dtd->paramEntities, - externalSubsetName, - sizeof(ENTITY)); - if (!declEntity) - return XML_ERROR_NO_MEMORY; -#endif /* XML_DTD */ - dtd->hasParamEntityRefs = XML_TRUE; - if (startDoctypeDeclHandler) { - XML_Char *pubId; - if (!XmlIsPublicId(enc, s, next, eventPP)) - return XML_ERROR_PUBLICID; - pubId = poolStoreString(&tempPool, enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!pubId) - return XML_ERROR_NO_MEMORY; - normalizePublicId(pubId); - poolFinish(&tempPool); - doctypePubid = pubId; - handleDefault = XML_FALSE; - goto alreadyChecked; - } - /* fall through */ - case XML_ROLE_ENTITY_PUBLIC_ID: - if (!XmlIsPublicId(enc, s, next, eventPP)) - return XML_ERROR_PUBLICID; - alreadyChecked: - if (dtd->keepProcessing && declEntity) { - XML_Char *tem = poolStoreString(&dtd->pool, - enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!tem) - return XML_ERROR_NO_MEMORY; - normalizePublicId(tem); - declEntity->publicId = tem; - poolFinish(&dtd->pool); - if (entityDeclHandler) - handleDefault = XML_FALSE; - } - break; - case XML_ROLE_DOCTYPE_CLOSE: - if (doctypeName) { - startDoctypeDeclHandler(handlerArg, doctypeName, - doctypeSysid, doctypePubid, 0); - poolClear(&tempPool); - handleDefault = XML_FALSE; - } - /* doctypeSysid will be non-NULL in the case of a previous - XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler - was not set, indicating an external subset - */ -#ifdef XML_DTD - if (doctypeSysid || useForeignDTD) { - XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; - dtd->hasParamEntityRefs = XML_TRUE; - if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(parser, - &dtd->paramEntities, - externalSubsetName, - sizeof(ENTITY)); - if (!entity) - return XML_ERROR_NO_MEMORY; - if (useForeignDTD) - entity->base = curBase; - dtd->paramEntityRead = XML_FALSE; - if (!externalEntityRefHandler(externalEntityRefHandlerArg, - 0, - entity->base, - entity->systemId, - entity->publicId)) - return XML_ERROR_EXTERNAL_ENTITY_HANDLING; - if (dtd->paramEntityRead) { - if (!dtd->standalone && - notStandaloneHandler && - !notStandaloneHandler(handlerArg)) - return XML_ERROR_NOT_STANDALONE; - } - /* if we didn't read the foreign DTD then this means that there - is no external subset and we must reset dtd->hasParamEntityRefs - */ - else if (!doctypeSysid) - dtd->hasParamEntityRefs = hadParamEntityRefs; - /* end of DTD - no need to update dtd->keepProcessing */ - } - useForeignDTD = XML_FALSE; - } -#endif /* XML_DTD */ - if (endDoctypeDeclHandler) { - endDoctypeDeclHandler(handlerArg); - handleDefault = XML_FALSE; - } - break; - case XML_ROLE_INSTANCE_START: -#ifdef XML_DTD - /* if there is no DOCTYPE declaration then now is the - last chance to read the foreign DTD - */ - if (useForeignDTD) { - XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; - dtd->hasParamEntityRefs = XML_TRUE; - if (paramEntityParsing && externalEntityRefHandler) { - ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities, - externalSubsetName, - sizeof(ENTITY)); - if (!entity) - return XML_ERROR_NO_MEMORY; - entity->base = curBase; - dtd->paramEntityRead = XML_FALSE; - if (!externalEntityRefHandler(externalEntityRefHandlerArg, - 0, - entity->base, - entity->systemId, - entity->publicId)) - return XML_ERROR_EXTERNAL_ENTITY_HANDLING; - if (dtd->paramEntityRead) { - if (!dtd->standalone && - notStandaloneHandler && - !notStandaloneHandler(handlerArg)) - return XML_ERROR_NOT_STANDALONE; - } - /* if we didn't read the foreign DTD then this means that there - is no external subset and we must reset dtd->hasParamEntityRefs - */ - else - dtd->hasParamEntityRefs = hadParamEntityRefs; - /* end of DTD - no need to update dtd->keepProcessing */ - } - } -#endif /* XML_DTD */ - processor = contentProcessor; - return contentProcessor(parser, s, end, nextPtr); - case XML_ROLE_ATTLIST_ELEMENT_NAME: - declElementType = getElementType(parser, enc, s, next); - if (!declElementType) - return XML_ERROR_NO_MEMORY; - goto checkAttListDeclHandler; - case XML_ROLE_ATTRIBUTE_NAME: - declAttributeId = getAttributeId(parser, enc, s, next); - if (!declAttributeId) - return XML_ERROR_NO_MEMORY; - declAttributeIsCdata = XML_FALSE; - declAttributeType = NULL; - declAttributeIsId = XML_FALSE; - goto checkAttListDeclHandler; - case XML_ROLE_ATTRIBUTE_TYPE_CDATA: - declAttributeIsCdata = XML_TRUE; - declAttributeType = atypeCDATA; - goto checkAttListDeclHandler; - case XML_ROLE_ATTRIBUTE_TYPE_ID: - declAttributeIsId = XML_TRUE; - declAttributeType = atypeID; - goto checkAttListDeclHandler; - case XML_ROLE_ATTRIBUTE_TYPE_IDREF: - declAttributeType = atypeIDREF; - goto checkAttListDeclHandler; - case XML_ROLE_ATTRIBUTE_TYPE_IDREFS: - declAttributeType = atypeIDREFS; - goto checkAttListDeclHandler; - case XML_ROLE_ATTRIBUTE_TYPE_ENTITY: - declAttributeType = atypeENTITY; - goto checkAttListDeclHandler; - case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES: - declAttributeType = atypeENTITIES; - goto checkAttListDeclHandler; - case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN: - declAttributeType = atypeNMTOKEN; - goto checkAttListDeclHandler; - case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS: - declAttributeType = atypeNMTOKENS; - checkAttListDeclHandler: - if (dtd->keepProcessing && attlistDeclHandler) - handleDefault = XML_FALSE; - break; - case XML_ROLE_ATTRIBUTE_ENUM_VALUE: - case XML_ROLE_ATTRIBUTE_NOTATION_VALUE: - if (dtd->keepProcessing && attlistDeclHandler) { - const XML_Char *prefix; - if (declAttributeType) { - prefix = enumValueSep; - } - else { - prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE - ? notationPrefix - : enumValueStart); - } - if (!poolAppendString(&tempPool, prefix)) - return XML_ERROR_NO_MEMORY; - if (!poolAppend(&tempPool, enc, s, next)) - return XML_ERROR_NO_MEMORY; - declAttributeType = tempPool.start; - handleDefault = XML_FALSE; - } - break; - case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE: - case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE: - if (dtd->keepProcessing) { - if (!defineAttribute(declElementType, declAttributeId, - declAttributeIsCdata, declAttributeIsId, - 0, parser)) - return XML_ERROR_NO_MEMORY; - if (attlistDeclHandler && declAttributeType) { - if (*declAttributeType == XML_T(ASCII_LPAREN) - || (*declAttributeType == XML_T(ASCII_N) - && declAttributeType[1] == XML_T(ASCII_O))) { - /* Enumerated or Notation type */ - if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN)) - || !poolAppendChar(&tempPool, XML_T('\0'))) - return XML_ERROR_NO_MEMORY; - declAttributeType = tempPool.start; - poolFinish(&tempPool); - } - *eventEndPP = s; - attlistDeclHandler(handlerArg, declElementType->name, - declAttributeId->name, declAttributeType, - 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); - poolClear(&tempPool); - handleDefault = XML_FALSE; - } - } - break; - case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: - case XML_ROLE_FIXED_ATTRIBUTE_VALUE: - if (dtd->keepProcessing) { - const XML_Char *attVal; - enum XML_Error result = - storeAttributeValue(parser, enc, declAttributeIsCdata, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar, - &dtd->pool); - if (result) - return result; - attVal = poolStart(&dtd->pool); - poolFinish(&dtd->pool); - /* ID attributes aren't allowed to have a default */ - if (!defineAttribute(declElementType, declAttributeId, - declAttributeIsCdata, XML_FALSE, attVal, parser)) - return XML_ERROR_NO_MEMORY; - if (attlistDeclHandler && declAttributeType) { - if (*declAttributeType == XML_T(ASCII_LPAREN) - || (*declAttributeType == XML_T(ASCII_N) - && declAttributeType[1] == XML_T(ASCII_O))) { - /* Enumerated or Notation type */ - if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN)) - || !poolAppendChar(&tempPool, XML_T('\0'))) - return XML_ERROR_NO_MEMORY; - declAttributeType = tempPool.start; - poolFinish(&tempPool); - } - *eventEndPP = s; - attlistDeclHandler(handlerArg, declElementType->name, - declAttributeId->name, declAttributeType, - attVal, - role == XML_ROLE_FIXED_ATTRIBUTE_VALUE); - poolClear(&tempPool); - handleDefault = XML_FALSE; - } - } - break; - case XML_ROLE_ENTITY_VALUE: - if (dtd->keepProcessing) { - enum XML_Error result = storeEntityValue(parser, enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (declEntity) { - declEntity->textPtr = poolStart(&dtd->entityValuePool); - declEntity->textLen = (int)(poolLength(&dtd->entityValuePool)); - poolFinish(&dtd->entityValuePool); - if (entityDeclHandler) { - *eventEndPP = s; - entityDeclHandler(handlerArg, - declEntity->name, - declEntity->is_param, - declEntity->textPtr, - declEntity->textLen, - curBase, 0, 0, 0); - handleDefault = XML_FALSE; - } - } - else - poolDiscard(&dtd->entityValuePool); - if (result != XML_ERROR_NONE) - return result; - } - break; - case XML_ROLE_DOCTYPE_SYSTEM_ID: -#ifdef XML_DTD - useForeignDTD = XML_FALSE; -#endif /* XML_DTD */ - dtd->hasParamEntityRefs = XML_TRUE; - if (startDoctypeDeclHandler) { - doctypeSysid = poolStoreString(&tempPool, enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (doctypeSysid == NULL) - return XML_ERROR_NO_MEMORY; - poolFinish(&tempPool); - handleDefault = XML_FALSE; - } -#ifdef XML_DTD - else - /* use externalSubsetName to make doctypeSysid non-NULL - for the case where no startDoctypeDeclHandler is set */ - doctypeSysid = externalSubsetName; -#endif /* XML_DTD */ - if (!dtd->standalone -#ifdef XML_DTD - && !paramEntityParsing -#endif /* XML_DTD */ - && notStandaloneHandler - && !notStandaloneHandler(handlerArg)) - return XML_ERROR_NOT_STANDALONE; -#ifndef XML_DTD - break; -#else /* XML_DTD */ - if (!declEntity) { - declEntity = (ENTITY *)lookup(parser, - &dtd->paramEntities, - externalSubsetName, - sizeof(ENTITY)); - if (!declEntity) - return XML_ERROR_NO_MEMORY; - declEntity->publicId = NULL; - } - /* fall through */ -#endif /* XML_DTD */ - case XML_ROLE_ENTITY_SYSTEM_ID: - if (dtd->keepProcessing && declEntity) { - declEntity->systemId = poolStoreString(&dtd->pool, enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!declEntity->systemId) - return XML_ERROR_NO_MEMORY; - declEntity->base = curBase; - poolFinish(&dtd->pool); - if (entityDeclHandler) - handleDefault = XML_FALSE; - } - break; - case XML_ROLE_ENTITY_COMPLETE: - if (dtd->keepProcessing && declEntity && entityDeclHandler) { - *eventEndPP = s; - entityDeclHandler(handlerArg, - declEntity->name, - declEntity->is_param, - 0,0, - declEntity->base, - declEntity->systemId, - declEntity->publicId, - 0); - handleDefault = XML_FALSE; - } - break; - case XML_ROLE_ENTITY_NOTATION_NAME: - if (dtd->keepProcessing && declEntity) { - declEntity->notation = poolStoreString(&dtd->pool, enc, s, next); - if (!declEntity->notation) - return XML_ERROR_NO_MEMORY; - poolFinish(&dtd->pool); - if (unparsedEntityDeclHandler) { - *eventEndPP = s; - unparsedEntityDeclHandler(handlerArg, - declEntity->name, - declEntity->base, - declEntity->systemId, - declEntity->publicId, - declEntity->notation); - handleDefault = XML_FALSE; - } - else if (entityDeclHandler) { - *eventEndPP = s; - entityDeclHandler(handlerArg, - declEntity->name, - 0,0,0, - declEntity->base, - declEntity->systemId, - declEntity->publicId, - declEntity->notation); - handleDefault = XML_FALSE; - } - } - break; - case XML_ROLE_GENERAL_ENTITY_NAME: - { - if (XmlPredefinedEntityName(enc, s, next)) { - declEntity = NULL; - break; - } - if (dtd->keepProcessing) { - const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); - if (!name) - return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, - sizeof(ENTITY)); - if (!declEntity) - return XML_ERROR_NO_MEMORY; - if (declEntity->name != name) { - poolDiscard(&dtd->pool); - declEntity = NULL; - } - else { - poolFinish(&dtd->pool); - declEntity->publicId = NULL; - declEntity->is_param = XML_FALSE; - /* if we have a parent parser or are reading an internal parameter - entity, then the entity declaration is not considered "internal" - */ - declEntity->is_internal = !(parentParser || openInternalEntities); - if (entityDeclHandler) - handleDefault = XML_FALSE; - } - } - else { - poolDiscard(&dtd->pool); - declEntity = NULL; - } - } - break; - case XML_ROLE_PARAM_ENTITY_NAME: -#ifdef XML_DTD - if (dtd->keepProcessing) { - const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); - if (!name) - return XML_ERROR_NO_MEMORY; - declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities, - name, sizeof(ENTITY)); - if (!declEntity) - return XML_ERROR_NO_MEMORY; - if (declEntity->name != name) { - poolDiscard(&dtd->pool); - declEntity = NULL; - } - else { - poolFinish(&dtd->pool); - declEntity->publicId = NULL; - declEntity->is_param = XML_TRUE; - /* if we have a parent parser or are reading an internal parameter - entity, then the entity declaration is not considered "internal" - */ - declEntity->is_internal = !(parentParser || openInternalEntities); - if (entityDeclHandler) - handleDefault = XML_FALSE; - } - } - else { - poolDiscard(&dtd->pool); - declEntity = NULL; - } -#else /* not XML_DTD */ - declEntity = NULL; -#endif /* XML_DTD */ - break; - case XML_ROLE_NOTATION_NAME: - declNotationPublicId = NULL; - declNotationName = NULL; - if (notationDeclHandler) { - declNotationName = poolStoreString(&tempPool, enc, s, next); - if (!declNotationName) - return XML_ERROR_NO_MEMORY; - poolFinish(&tempPool); - handleDefault = XML_FALSE; - } - break; - case XML_ROLE_NOTATION_PUBLIC_ID: - if (!XmlIsPublicId(enc, s, next, eventPP)) - return XML_ERROR_PUBLICID; - if (declNotationName) { /* means notationDeclHandler != NULL */ - XML_Char *tem = poolStoreString(&tempPool, - enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!tem) - return XML_ERROR_NO_MEMORY; - normalizePublicId(tem); - declNotationPublicId = tem; - poolFinish(&tempPool); - handleDefault = XML_FALSE; - } - break; - case XML_ROLE_NOTATION_SYSTEM_ID: - if (declNotationName && notationDeclHandler) { - const XML_Char *systemId - = poolStoreString(&tempPool, enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!systemId) - return XML_ERROR_NO_MEMORY; - *eventEndPP = s; - notationDeclHandler(handlerArg, - declNotationName, - curBase, - systemId, - declNotationPublicId); - handleDefault = XML_FALSE; - } - poolClear(&tempPool); - break; - case XML_ROLE_NOTATION_NO_SYSTEM_ID: - if (declNotationPublicId && notationDeclHandler) { - *eventEndPP = s; - notationDeclHandler(handlerArg, - declNotationName, - curBase, - 0, - declNotationPublicId); - handleDefault = XML_FALSE; - } - poolClear(&tempPool); - break; - case XML_ROLE_ERROR: - switch (tok) { - case XML_TOK_PARAM_ENTITY_REF: - /* PE references in internal subset are - not allowed within declarations. */ - return XML_ERROR_PARAM_ENTITY_REF; - case XML_TOK_XML_DECL: - return XML_ERROR_MISPLACED_XML_PI; - default: - return XML_ERROR_SYNTAX; - } -#ifdef XML_DTD - case XML_ROLE_IGNORE_SECT: - { - enum XML_Error result; - if (defaultHandler) - reportDefault(parser, enc, s, next); - handleDefault = XML_FALSE; - result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore); - if (result != XML_ERROR_NONE) - return result; - else if (!next) { - processor = ignoreSectionProcessor; - return result; - } - } - break; -#endif /* XML_DTD */ - case XML_ROLE_GROUP_OPEN: - if (prologState.level >= groupSize) { - if (groupSize) { - char *temp = (char *)REALLOC(groupConnector, groupSize *= 2); - if (temp == NULL) - return XML_ERROR_NO_MEMORY; - groupConnector = temp; - if (dtd->scaffIndex) { - int *temp = (int *)REALLOC(dtd->scaffIndex, - groupSize * sizeof(int)); - if (temp == NULL) - return XML_ERROR_NO_MEMORY; - dtd->scaffIndex = temp; - } - } - else { - groupConnector = (char *)MALLOC(groupSize = 32); - if (!groupConnector) - return XML_ERROR_NO_MEMORY; - } - } - groupConnector[prologState.level] = 0; - if (dtd->in_eldecl) { - int myindex = nextScaffoldPart(parser); - if (myindex < 0) - return XML_ERROR_NO_MEMORY; - dtd->scaffIndex[dtd->scaffLevel] = myindex; - dtd->scaffLevel++; - dtd->scaffold[myindex].type = XML_CTYPE_SEQ; - if (elementDeclHandler) - handleDefault = XML_FALSE; - } - break; - case XML_ROLE_GROUP_SEQUENCE: - if (groupConnector[prologState.level] == ASCII_PIPE) - return XML_ERROR_SYNTAX; - groupConnector[prologState.level] = ASCII_COMMA; - if (dtd->in_eldecl && elementDeclHandler) - handleDefault = XML_FALSE; - break; - case XML_ROLE_GROUP_CHOICE: - if (groupConnector[prologState.level] == ASCII_COMMA) - return XML_ERROR_SYNTAX; - if (dtd->in_eldecl - && !groupConnector[prologState.level] - && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type - != XML_CTYPE_MIXED) - ) { - dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type - = XML_CTYPE_CHOICE; - if (elementDeclHandler) - handleDefault = XML_FALSE; - } - groupConnector[prologState.level] = ASCII_PIPE; - break; - case XML_ROLE_PARAM_ENTITY_REF: -#ifdef XML_DTD - case XML_ROLE_INNER_PARAM_ENTITY_REF: - dtd->hasParamEntityRefs = XML_TRUE; - if (!paramEntityParsing) - dtd->keepProcessing = dtd->standalone; - else { - const XML_Char *name; - ENTITY *entity; - name = poolStoreString(&dtd->pool, enc, - s + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!name) - return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); - poolDiscard(&dtd->pool); - /* first, determine if a check for an existing declaration is needed; - if yes, check that the entity exists, and that it is internal, - otherwise call the skipped entity handler - */ - if (prologState.documentEntity && - (dtd->standalone - ? !openInternalEntities - : !dtd->hasParamEntityRefs)) { - if (!entity) - return XML_ERROR_UNDEFINED_ENTITY; - else if (!entity->is_internal) - return XML_ERROR_ENTITY_DECLARED_IN_PE; - } - else if (!entity) { - dtd->keepProcessing = dtd->standalone; - /* cannot report skipped entities in declarations */ - if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) { - skippedEntityHandler(handlerArg, name, 1); - handleDefault = XML_FALSE; - } - break; - } - if (entity->open) - return XML_ERROR_RECURSIVE_ENTITY_REF; - if (entity->textPtr) { - enum XML_Error result; - XML_Bool betweenDecl = - (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE); - result = processInternalEntity(parser, entity, betweenDecl); - if (result != XML_ERROR_NONE) - return result; - handleDefault = XML_FALSE; - break; - } - if (externalEntityRefHandler) { - dtd->paramEntityRead = XML_FALSE; - entity->open = XML_TRUE; - if (!externalEntityRefHandler(externalEntityRefHandlerArg, - 0, - entity->base, - entity->systemId, - entity->publicId)) { - entity->open = XML_FALSE; - return XML_ERROR_EXTERNAL_ENTITY_HANDLING; - } - entity->open = XML_FALSE; - handleDefault = XML_FALSE; - if (!dtd->paramEntityRead) { - dtd->keepProcessing = dtd->standalone; - break; - } - } - else { - dtd->keepProcessing = dtd->standalone; - break; - } - } -#endif /* XML_DTD */ - if (!dtd->standalone && - notStandaloneHandler && - !notStandaloneHandler(handlerArg)) - return XML_ERROR_NOT_STANDALONE; - break; - - /* Element declaration stuff */ - - case XML_ROLE_ELEMENT_NAME: - if (elementDeclHandler) { - declElementType = getElementType(parser, enc, s, next); - if (!declElementType) - return XML_ERROR_NO_MEMORY; - dtd->scaffLevel = 0; - dtd->scaffCount = 0; - dtd->in_eldecl = XML_TRUE; - handleDefault = XML_FALSE; - } - break; - - case XML_ROLE_CONTENT_ANY: - case XML_ROLE_CONTENT_EMPTY: - if (dtd->in_eldecl) { - if (elementDeclHandler) { - XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content)); - if (!content) - return XML_ERROR_NO_MEMORY; - content->quant = XML_CQUANT_NONE; - content->name = NULL; - content->numchildren = 0; - content->children = NULL; - content->type = ((role == XML_ROLE_CONTENT_ANY) ? - XML_CTYPE_ANY : - XML_CTYPE_EMPTY); - *eventEndPP = s; - elementDeclHandler(handlerArg, declElementType->name, content); - handleDefault = XML_FALSE; - } - dtd->in_eldecl = XML_FALSE; - } - break; - - case XML_ROLE_CONTENT_PCDATA: - if (dtd->in_eldecl) { - dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type - = XML_CTYPE_MIXED; - if (elementDeclHandler) - handleDefault = XML_FALSE; - } - break; - - case XML_ROLE_CONTENT_ELEMENT: - quant = XML_CQUANT_NONE; - goto elementContent; - case XML_ROLE_CONTENT_ELEMENT_OPT: - quant = XML_CQUANT_OPT; - goto elementContent; - case XML_ROLE_CONTENT_ELEMENT_REP: - quant = XML_CQUANT_REP; - goto elementContent; - case XML_ROLE_CONTENT_ELEMENT_PLUS: - quant = XML_CQUANT_PLUS; - elementContent: - if (dtd->in_eldecl) { - ELEMENT_TYPE *el; - const XML_Char *name; - int nameLen; - const char *nxt = (quant == XML_CQUANT_NONE - ? next - : next - enc->minBytesPerChar); - int myindex = nextScaffoldPart(parser); - if (myindex < 0) - return XML_ERROR_NO_MEMORY; - dtd->scaffold[myindex].type = XML_CTYPE_NAME; - dtd->scaffold[myindex].quant = quant; - el = getElementType(parser, enc, s, nxt); - if (!el) - return XML_ERROR_NO_MEMORY; - name = el->name; - dtd->scaffold[myindex].name = name; - nameLen = 0; - for (; name[nameLen++]; ); - dtd->contentStringLen += nameLen; - if (elementDeclHandler) - handleDefault = XML_FALSE; - } - break; - - case XML_ROLE_GROUP_CLOSE: - quant = XML_CQUANT_NONE; - goto closeGroup; - case XML_ROLE_GROUP_CLOSE_OPT: - quant = XML_CQUANT_OPT; - goto closeGroup; - case XML_ROLE_GROUP_CLOSE_REP: - quant = XML_CQUANT_REP; - goto closeGroup; - case XML_ROLE_GROUP_CLOSE_PLUS: - quant = XML_CQUANT_PLUS; - closeGroup: - if (dtd->in_eldecl) { - if (elementDeclHandler) - handleDefault = XML_FALSE; - dtd->scaffLevel--; - dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant; - if (dtd->scaffLevel == 0) { - if (!handleDefault) { - XML_Content *model = build_model(parser); - if (!model) - return XML_ERROR_NO_MEMORY; - *eventEndPP = s; - elementDeclHandler(handlerArg, declElementType->name, model); - } - dtd->in_eldecl = XML_FALSE; - dtd->contentStringLen = 0; - } - } - break; - /* End element declaration stuff */ - - case XML_ROLE_PI: - if (!reportProcessingInstruction(parser, enc, s, next)) - return XML_ERROR_NO_MEMORY; - handleDefault = XML_FALSE; - break; - case XML_ROLE_COMMENT: - if (!reportComment(parser, enc, s, next)) - return XML_ERROR_NO_MEMORY; - handleDefault = XML_FALSE; - break; - case XML_ROLE_NONE: - switch (tok) { - case XML_TOK_BOM: - handleDefault = XML_FALSE; - break; - } - break; - case XML_ROLE_DOCTYPE_NONE: - if (startDoctypeDeclHandler) - handleDefault = XML_FALSE; - break; - case XML_ROLE_ENTITY_NONE: - if (dtd->keepProcessing && entityDeclHandler) - handleDefault = XML_FALSE; - break; - case XML_ROLE_NOTATION_NONE: - if (notationDeclHandler) - handleDefault = XML_FALSE; - break; - case XML_ROLE_ATTLIST_NONE: - if (dtd->keepProcessing && attlistDeclHandler) - handleDefault = XML_FALSE; - break; - case XML_ROLE_ELEMENT_NONE: - if (elementDeclHandler) - handleDefault = XML_FALSE; - break; - } /* end of big switch */ - - if (handleDefault && defaultHandler) - reportDefault(parser, enc, s, next); - - switch (ps_parsing) { - case XML_SUSPENDED: - *nextPtr = next; - return XML_ERROR_NONE; - case XML_FINISHED: - return XML_ERROR_ABORTED; - default: - s = next; - tok = XmlPrologTok(enc, s, end, &next); - } - } - /* not reached */ -} - -static enum XML_Error PTRCALL -epilogProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - processor = epilogProcessor; - eventPtr = s; - for (;;) { - const char *next = NULL; - int tok = XmlPrologTok(encoding, s, end, &next); - eventEndPtr = next; - switch (tok) { - /* report partial linebreak - it might be the last token */ - case -XML_TOK_PROLOG_S: - if (defaultHandler) { - reportDefault(parser, encoding, s, next); - if (ps_parsing == XML_FINISHED) - return XML_ERROR_ABORTED; - } - *nextPtr = next; - return XML_ERROR_NONE; - case XML_TOK_NONE: - *nextPtr = s; - return XML_ERROR_NONE; - case XML_TOK_PROLOG_S: - if (defaultHandler) - reportDefault(parser, encoding, s, next); - break; - case XML_TOK_PI: - if (!reportProcessingInstruction(parser, encoding, s, next)) - return XML_ERROR_NO_MEMORY; - break; - case XML_TOK_COMMENT: - if (!reportComment(parser, encoding, s, next)) - return XML_ERROR_NO_MEMORY; - break; - case XML_TOK_INVALID: - eventPtr = next; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL: - if (!ps_finalBuffer) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_UNCLOSED_TOKEN; - case XML_TOK_PARTIAL_CHAR: - if (!ps_finalBuffer) { - *nextPtr = s; - return XML_ERROR_NONE; - } - return XML_ERROR_PARTIAL_CHAR; - default: - return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; - } - eventPtr = s = next; - switch (ps_parsing) { - case XML_SUSPENDED: - *nextPtr = next; - return XML_ERROR_NONE; - case XML_FINISHED: - return XML_ERROR_ABORTED; - default: ; - } - } -} - -static enum XML_Error -processInternalEntity(XML_Parser parser, ENTITY *entity, - XML_Bool betweenDecl) -{ - const char *textStart, *textEnd; - const char *next; - enum XML_Error result; - OPEN_INTERNAL_ENTITY *openEntity; - - if (freeInternalEntities) { - openEntity = freeInternalEntities; - freeInternalEntities = openEntity->next; - } - else { - openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY)); - if (!openEntity) - return XML_ERROR_NO_MEMORY; - } - entity->open = XML_TRUE; - entity->processed = 0; - openEntity->next = openInternalEntities; - openInternalEntities = openEntity; - openEntity->entity = entity; - openEntity->startTagLevel = tagLevel; - openEntity->betweenDecl = betweenDecl; - openEntity->internalEventPtr = NULL; - openEntity->internalEventEndPtr = NULL; - textStart = (char *)entity->textPtr; - textEnd = (char *)(entity->textPtr + entity->textLen); - -#ifdef XML_DTD - if (entity->is_param) { - int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); - result = doProlog(parser, internalEncoding, textStart, textEnd, tok, - next, &next, XML_FALSE); - } - else -#endif /* XML_DTD */ - result = doContent(parser, tagLevel, internalEncoding, textStart, - textEnd, &next, XML_FALSE); - - if (result == XML_ERROR_NONE) { - if (textEnd != next && ps_parsing == XML_SUSPENDED) { - entity->processed = (int)(next - textStart); - processor = internalEntityProcessor; - } - else { - entity->open = XML_FALSE; - openInternalEntities = openEntity->next; - /* put openEntity back in list of free instances */ - openEntity->next = freeInternalEntities; - freeInternalEntities = openEntity; - } - } - return result; -} - -static enum XML_Error PTRCALL -internalEntityProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - ENTITY *entity; - const char *textStart, *textEnd; - const char *next; - enum XML_Error result; - OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities; - if (!openEntity) - return XML_ERROR_UNEXPECTED_STATE; - - entity = openEntity->entity; - textStart = ((char *)entity->textPtr) + entity->processed; - textEnd = (char *)(entity->textPtr + entity->textLen); - -#ifdef XML_DTD - if (entity->is_param) { - int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); - result = doProlog(parser, internalEncoding, textStart, textEnd, tok, - next, &next, XML_FALSE); - } - else -#endif /* XML_DTD */ - result = doContent(parser, openEntity->startTagLevel, internalEncoding, - textStart, textEnd, &next, XML_FALSE); - - if (result != XML_ERROR_NONE) - return result; - else if (textEnd != next && ps_parsing == XML_SUSPENDED) { - entity->processed = (int)(next - (char *)entity->textPtr); - return result; - } - else { - entity->open = XML_FALSE; - openInternalEntities = openEntity->next; - /* put openEntity back in list of free instances */ - openEntity->next = freeInternalEntities; - freeInternalEntities = openEntity; - } - -#ifdef XML_DTD - if (entity->is_param) { - int tok; - processor = prologProcessor; - tok = XmlPrologTok(encoding, s, end, &next); - return doProlog(parser, encoding, s, end, tok, next, nextPtr, - (XML_Bool)!ps_finalBuffer); - } - else -#endif /* XML_DTD */ - { - processor = contentProcessor; - /* see externalEntityContentProcessor vs contentProcessor */ - return doContent(parser, parentParser ? 1 : 0, encoding, s, end, - nextPtr, (XML_Bool)!ps_finalBuffer); - } -} - -static enum XML_Error PTRCALL -errorProcessor(XML_Parser parser, - const char *s, - const char *end, - const char **nextPtr) -{ - return errorCode; -} - -static enum XML_Error -storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, - const char *ptr, const char *end, - STRING_POOL *pool) -{ - enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, - end, pool); - if (result) - return result; - if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20) - poolChop(pool); - if (!poolAppendChar(pool, XML_T('\0'))) - return XML_ERROR_NO_MEMORY; - return XML_ERROR_NONE; -} - -static enum XML_Error -appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, - const char *ptr, const char *end, - STRING_POOL *pool) -{ - DTD * const dtd = _dtd; /* save one level of indirection */ - for (;;) { - const char *next; - int tok = XmlAttributeValueTok(enc, ptr, end, &next); - switch (tok) { - case XML_TOK_NONE: - return XML_ERROR_NONE; - case XML_TOK_INVALID: - if (enc == encoding) - eventPtr = next; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_PARTIAL: - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_INVALID_TOKEN; - case XML_TOK_CHAR_REF: - { - XML_Char buf[XML_ENCODE_MAX]; - int i; - int n = XmlCharRefNumber(enc, ptr); - if (n < 0) { - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_BAD_CHAR_REF; - } - if (!isCdata - && n == 0x20 /* space */ - && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) - break; - n = XmlEncode(n, (ICHAR *)buf); - if (!n) { - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_BAD_CHAR_REF; - } - for (i = 0; i < n; i++) { - if (!poolAppendChar(pool, buf[i])) - return XML_ERROR_NO_MEMORY; - } - } - break; - case XML_TOK_DATA_CHARS: - if (!poolAppend(pool, enc, ptr, next)) - return XML_ERROR_NO_MEMORY; - break; - case XML_TOK_TRAILING_CR: - next = ptr + enc->minBytesPerChar; - /* fall through */ - case XML_TOK_ATTRIBUTE_VALUE_S: - case XML_TOK_DATA_NEWLINE: - if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) - break; - if (!poolAppendChar(pool, 0x20)) - return XML_ERROR_NO_MEMORY; - break; - case XML_TOK_ENTITY_REF: - { - const XML_Char *name; - ENTITY *entity; - char checkEntityDecl; - XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc, - ptr + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (ch) { - if (!poolAppendChar(pool, ch)) - return XML_ERROR_NO_MEMORY; - break; - } - name = poolStoreString(&temp2Pool, enc, - ptr + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!name) - return XML_ERROR_NO_MEMORY; - entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0); - poolDiscard(&temp2Pool); - /* First, determine if a check for an existing declaration is needed; - if yes, check that the entity exists, and that it is internal. - */ - if (pool == &dtd->pool) /* are we called from prolog? */ - checkEntityDecl = -#ifdef XML_DTD - prologState.documentEntity && -#endif /* XML_DTD */ - (dtd->standalone - ? !openInternalEntities - : !dtd->hasParamEntityRefs); - else /* if (pool == &tempPool): we are called from content */ - checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone; - if (checkEntityDecl) { - if (!entity) - return XML_ERROR_UNDEFINED_ENTITY; - else if (!entity->is_internal) - return XML_ERROR_ENTITY_DECLARED_IN_PE; - } - else if (!entity) { - /* Cannot report skipped entity here - see comments on - skippedEntityHandler. - if (skippedEntityHandler) - skippedEntityHandler(handlerArg, name, 0); - */ - /* Cannot call the default handler because this would be - out of sync with the call to the startElementHandler. - if ((pool == &tempPool) && defaultHandler) - reportDefault(parser, enc, ptr, next); - */ - break; - } - if (entity->open) { - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_RECURSIVE_ENTITY_REF; - } - if (entity->notation) { - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_BINARY_ENTITY_REF; - } - if (!entity->textPtr) { - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; - } - else { - enum XML_Error result; - const XML_Char *textEnd = entity->textPtr + entity->textLen; - entity->open = XML_TRUE; - result = appendAttributeValue(parser, internalEncoding, isCdata, - (char *)entity->textPtr, - (char *)textEnd, pool); - entity->open = XML_FALSE; - if (result) - return result; - } - } - break; - default: - if (enc == encoding) - eventPtr = ptr; - return XML_ERROR_UNEXPECTED_STATE; - } - ptr = next; - } - /* not reached */ -} - -static enum XML_Error -storeEntityValue(XML_Parser parser, - const ENCODING *enc, - const char *entityTextPtr, - const char *entityTextEnd) -{ - DTD * const dtd = _dtd; /* save one level of indirection */ - STRING_POOL *pool = &(dtd->entityValuePool); - enum XML_Error result = XML_ERROR_NONE; -#ifdef XML_DTD - int oldInEntityValue = prologState.inEntityValue; - prologState.inEntityValue = 1; -#endif /* XML_DTD */ - /* never return Null for the value argument in EntityDeclHandler, - since this would indicate an external entity; therefore we - have to make sure that entityValuePool.start is not null */ - if (!pool->blocks) { - if (!poolGrow(pool)) - return XML_ERROR_NO_MEMORY; - } - - for (;;) { - const char *next; - int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next); - switch (tok) { - case XML_TOK_PARAM_ENTITY_REF: -#ifdef XML_DTD - if (isParamEntity || enc != encoding) { - const XML_Char *name; - ENTITY *entity; - name = poolStoreString(&tempPool, enc, - entityTextPtr + enc->minBytesPerChar, - next - enc->minBytesPerChar); - if (!name) { - result = XML_ERROR_NO_MEMORY; - goto endEntityValue; - } - entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0); - poolDiscard(&tempPool); - if (!entity) { - /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ - /* cannot report skipped entity here - see comments on - skippedEntityHandler - if (skippedEntityHandler) - skippedEntityHandler(handlerArg, name, 0); - */ - dtd->keepProcessing = dtd->standalone; - goto endEntityValue; - } - if (entity->open) { - if (enc == encoding) - eventPtr = entityTextPtr; - result = XML_ERROR_RECURSIVE_ENTITY_REF; - goto endEntityValue; - } - if (entity->systemId) { - if (externalEntityRefHandler) { - dtd->paramEntityRead = XML_FALSE; - entity->open = XML_TRUE; - if (!externalEntityRefHandler(externalEntityRefHandlerArg, - 0, - entity->base, - entity->systemId, - entity->publicId)) { - entity->open = XML_FALSE; - result = XML_ERROR_EXTERNAL_ENTITY_HANDLING; - goto endEntityValue; - } - entity->open = XML_FALSE; - if (!dtd->paramEntityRead) - dtd->keepProcessing = dtd->standalone; - } - else - dtd->keepProcessing = dtd->standalone; - } - else { - entity->open = XML_TRUE; - result = storeEntityValue(parser, - internalEncoding, - (char *)entity->textPtr, - (char *)(entity->textPtr - + entity->textLen)); - entity->open = XML_FALSE; - if (result) - goto endEntityValue; - } - break; - } -#endif /* XML_DTD */ - /* In the internal subset, PE references are not legal - within markup declarations, e.g entity values in this case. */ - eventPtr = entityTextPtr; - result = XML_ERROR_PARAM_ENTITY_REF; - goto endEntityValue; - case XML_TOK_NONE: - result = XML_ERROR_NONE; - goto endEntityValue; - case XML_TOK_ENTITY_REF: - case XML_TOK_DATA_CHARS: - if (!poolAppend(pool, enc, entityTextPtr, next)) { - result = XML_ERROR_NO_MEMORY; - goto endEntityValue; - } - break; - case XML_TOK_TRAILING_CR: - next = entityTextPtr + enc->minBytesPerChar; - /* fall through */ - case XML_TOK_DATA_NEWLINE: - if (pool->end == pool->ptr && !poolGrow(pool)) { - result = XML_ERROR_NO_MEMORY; - goto endEntityValue; - } - *(pool->ptr)++ = 0xA; - break; - case XML_TOK_CHAR_REF: - { - XML_Char buf[XML_ENCODE_MAX]; - int i; - int n = XmlCharRefNumber(enc, entityTextPtr); - if (n < 0) { - if (enc == encoding) - eventPtr = entityTextPtr; - result = XML_ERROR_BAD_CHAR_REF; - goto endEntityValue; - } - n = XmlEncode(n, (ICHAR *)buf); - if (!n) { - if (enc == encoding) - eventPtr = entityTextPtr; - result = XML_ERROR_BAD_CHAR_REF; - goto endEntityValue; - } - for (i = 0; i < n; i++) { - if (pool->end == pool->ptr && !poolGrow(pool)) { - result = XML_ERROR_NO_MEMORY; - goto endEntityValue; - } - *(pool->ptr)++ = buf[i]; - } - } - break; - case XML_TOK_PARTIAL: - if (enc == encoding) - eventPtr = entityTextPtr; - result = XML_ERROR_INVALID_TOKEN; - goto endEntityValue; - case XML_TOK_INVALID: - if (enc == encoding) - eventPtr = next; - result = XML_ERROR_INVALID_TOKEN; - goto endEntityValue; - default: - if (enc == encoding) - eventPtr = entityTextPtr; - result = XML_ERROR_UNEXPECTED_STATE; - goto endEntityValue; - } - entityTextPtr = next; - } -endEntityValue: -#ifdef XML_DTD - prologState.inEntityValue = oldInEntityValue; -#endif /* XML_DTD */ - return result; -} - -static void FASTCALL -normalizeLines(XML_Char *s) -{ - XML_Char *p; - for (;; s++) { - if (*s == XML_T('\0')) - return; - if (*s == 0xD) - break; - } - p = s; - do { - if (*s == 0xD) { - *p++ = 0xA; - if (*++s == 0xA) - s++; - } - else - *p++ = *s++; - } while (*s); - *p = XML_T('\0'); -} - -static int -reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, - const char *start, const char *end) -{ - const XML_Char *target; - XML_Char *data; - const char *tem; - if (!processingInstructionHandler) { - if (defaultHandler) - reportDefault(parser, enc, start, end); - return 1; - } - start += enc->minBytesPerChar * 2; - tem = start + XmlNameLength(enc, start); - target = poolStoreString(&tempPool, enc, start, tem); - if (!target) - return 0; - poolFinish(&tempPool); - data = poolStoreString(&tempPool, enc, - XmlSkipS(enc, tem), - end - enc->minBytesPerChar*2); - if (!data) - return 0; - normalizeLines(data); - processingInstructionHandler(handlerArg, target, data); - poolClear(&tempPool); - return 1; -} - -static int -reportComment(XML_Parser parser, const ENCODING *enc, - const char *start, const char *end) -{ - XML_Char *data; - if (!commentHandler) { - if (defaultHandler) - reportDefault(parser, enc, start, end); - return 1; - } - data = poolStoreString(&tempPool, - enc, - start + enc->minBytesPerChar * 4, - end - enc->minBytesPerChar * 3); - if (!data) - return 0; - normalizeLines(data); - commentHandler(handlerArg, data); - poolClear(&tempPool); - return 1; -} - -static void -reportDefault(XML_Parser parser, const ENCODING *enc, - const char *s, const char *end) -{ - if (MUST_CONVERT(enc, s)) { - const char **eventPP; - const char **eventEndPP; - if (enc == encoding) { - eventPP = &eventPtr; - eventEndPP = &eventEndPtr; - } - else { - eventPP = &(openInternalEntities->internalEventPtr); - eventEndPP = &(openInternalEntities->internalEventEndPtr); - } - do { - ICHAR *dataPtr = (ICHAR *)dataBuf; - XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); - *eventEndPP = s; - defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf)); - *eventPP = s; - } while (s != end); - } - else - defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s)); -} - - -static int -defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, - XML_Bool isId, const XML_Char *value, XML_Parser parser) -{ - DEFAULT_ATTRIBUTE *att; - if (value || isId) { - /* The handling of default attributes gets messed up if we have - a default which duplicates a non-default. */ - int i; - for (i = 0; i < type->nDefaultAtts; i++) - if (attId == type->defaultAtts[i].id) - return 1; - if (isId && !type->idAtt && !attId->xmlns) - type->idAtt = attId; - } - if (type->nDefaultAtts == type->allocDefaultAtts) { - if (type->allocDefaultAtts == 0) { - type->allocDefaultAtts = 8; - type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts - * sizeof(DEFAULT_ATTRIBUTE)); - if (!type->defaultAtts) - return 0; - } - else { - DEFAULT_ATTRIBUTE *temp; - int count = type->allocDefaultAtts * 2; - temp = (DEFAULT_ATTRIBUTE *) - REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE))); - if (temp == NULL) - return 0; - type->allocDefaultAtts = count; - type->defaultAtts = temp; - } - } - att = type->defaultAtts + type->nDefaultAtts; - att->id = attId; - att->value = value; - att->isCdata = isCdata; - if (!isCdata) - attId->maybeTokenized = XML_TRUE; - type->nDefaultAtts += 1; - return 1; -} - -static int -setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) -{ - DTD * const dtd = _dtd; /* save one level of indirection */ - const XML_Char *name; - for (name = elementType->name; *name; name++) { - if (*name == XML_T(ASCII_COLON)) { - PREFIX *prefix; - const XML_Char *s; - for (s = elementType->name; s != name; s++) { - if (!poolAppendChar(&dtd->pool, *s)) - return 0; - } - if (!poolAppendChar(&dtd->pool, XML_T('\0'))) - return 0; - prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), - sizeof(PREFIX)); - if (!prefix) - return 0; - if (prefix->name == poolStart(&dtd->pool)) - poolFinish(&dtd->pool); - else - poolDiscard(&dtd->pool); - elementType->prefix = prefix; - - } - } - return 1; -} - -static ATTRIBUTE_ID * -getAttributeId(XML_Parser parser, const ENCODING *enc, - const char *start, const char *end) -{ - DTD * const dtd = _dtd; /* save one level of indirection */ - ATTRIBUTE_ID *id; - const XML_Char *name; - if (!poolAppendChar(&dtd->pool, XML_T('\0'))) - return NULL; - name = poolStoreString(&dtd->pool, enc, start, end); - if (!name) - return NULL; - /* skip quotation mark - its storage will be re-used (like in name[-1]) */ - ++name; - id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); - if (!id) - return NULL; - if (id->name != name) - poolDiscard(&dtd->pool); - else { - poolFinish(&dtd->pool); - if (!ns) - ; - else if (name[0] == XML_T(ASCII_x) - && name[1] == XML_T(ASCII_m) - && name[2] == XML_T(ASCII_l) - && name[3] == XML_T(ASCII_n) - && name[4] == XML_T(ASCII_s) - && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) { - if (name[5] == XML_T('\0')) - id->prefix = &dtd->defaultPrefix; - else - id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX)); - id->xmlns = XML_TRUE; - } - else { - int i; - for (i = 0; name[i]; i++) { - /* attributes without prefix are *not* in the default namespace */ - if (name[i] == XML_T(ASCII_COLON)) { - int j; - for (j = 0; j < i; j++) { - if (!poolAppendChar(&dtd->pool, name[j])) - return NULL; - } - if (!poolAppendChar(&dtd->pool, XML_T('\0'))) - return NULL; - id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool), - sizeof(PREFIX)); - if (id->prefix->name == poolStart(&dtd->pool)) - poolFinish(&dtd->pool); - else - poolDiscard(&dtd->pool); - break; - } - } - } - } - return id; -} - -#define CONTEXT_SEP XML_T(ASCII_FF) - -static const XML_Char * -getContext(XML_Parser parser) -{ - DTD * const dtd = _dtd; /* save one level of indirection */ - HASH_TABLE_ITER iter; - XML_Bool needSep = XML_FALSE; - - if (dtd->defaultPrefix.binding) { - int i; - int len; - if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS))) - return NULL; - len = dtd->defaultPrefix.binding->uriLen; - if (namespaceSeparator) - len--; - for (i = 0; i < len; i++) - if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i])) - return NULL; - needSep = XML_TRUE; - } - - hashTableIterInit(&iter, &(dtd->prefixes)); - for (;;) { - int i; - int len; - const XML_Char *s; - PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter); - if (!prefix) - break; - if (!prefix->binding) - continue; - if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) - return NULL; - for (s = prefix->name; *s; s++) - if (!poolAppendChar(&tempPool, *s)) - return NULL; - if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS))) - return NULL; - len = prefix->binding->uriLen; - if (namespaceSeparator) - len--; - for (i = 0; i < len; i++) - if (!poolAppendChar(&tempPool, prefix->binding->uri[i])) - return NULL; - needSep = XML_TRUE; - } - - - hashTableIterInit(&iter, &(dtd->generalEntities)); - for (;;) { - const XML_Char *s; - ENTITY *e = (ENTITY *)hashTableIterNext(&iter); - if (!e) - break; - if (!e->open) - continue; - if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) - return NULL; - for (s = e->name; *s; s++) - if (!poolAppendChar(&tempPool, *s)) - return 0; - needSep = XML_TRUE; - } - - if (!poolAppendChar(&tempPool, XML_T('\0'))) - return NULL; - return tempPool.start; -} - -static XML_Bool -setContext(XML_Parser parser, const XML_Char *context) -{ - DTD * const dtd = _dtd; /* save one level of indirection */ - const XML_Char *s = context; - - while (*context != XML_T('\0')) { - if (*s == CONTEXT_SEP || *s == XML_T('\0')) { - ENTITY *e; - if (!poolAppendChar(&tempPool, XML_T('\0'))) - return XML_FALSE; - e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0); - if (e) - e->open = XML_TRUE; - if (*s != XML_T('\0')) - s++; - context = s; - poolDiscard(&tempPool); - } - else if (*s == XML_T(ASCII_EQUALS)) { - PREFIX *prefix; - if (poolLength(&tempPool) == 0) - prefix = &dtd->defaultPrefix; - else { - if (!poolAppendChar(&tempPool, XML_T('\0'))) - return XML_FALSE; - prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool), - sizeof(PREFIX)); - if (!prefix) - return XML_FALSE; - if (prefix->name == poolStart(&tempPool)) { - prefix->name = poolCopyString(&dtd->pool, prefix->name); - if (!prefix->name) - return XML_FALSE; - } - poolDiscard(&tempPool); - } - for (context = s + 1; - *context != CONTEXT_SEP && *context != XML_T('\0'); - context++) - if (!poolAppendChar(&tempPool, *context)) - return XML_FALSE; - if (!poolAppendChar(&tempPool, XML_T('\0'))) - return XML_FALSE; - if (addBinding(parser, prefix, NULL, poolStart(&tempPool), - &inheritedBindings) != XML_ERROR_NONE) - return XML_FALSE; - poolDiscard(&tempPool); - if (*context != XML_T('\0')) - ++context; - s = context; - } - else { - if (!poolAppendChar(&tempPool, *s)) - return XML_FALSE; - s++; - } - } - return XML_TRUE; -} - -static void FASTCALL -normalizePublicId(XML_Char *publicId) -{ - XML_Char *p = publicId; - XML_Char *s; - for (s = publicId; *s; s++) { - switch (*s) { - case 0x20: - case 0xD: - case 0xA: - if (p != publicId && p[-1] != 0x20) - *p++ = 0x20; - break; - default: - *p++ = *s; - } - } - if (p != publicId && p[-1] == 0x20) - --p; - *p = XML_T('\0'); -} - -static DTD * -dtdCreate(const XML_Memory_Handling_Suite *ms) -{ - DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD)); - if (p == NULL) - return p; - poolInit(&(p->pool), ms); - poolInit(&(p->entityValuePool), ms); - hashTableInit(&(p->generalEntities), ms); - hashTableInit(&(p->elementTypes), ms); - hashTableInit(&(p->attributeIds), ms); - hashTableInit(&(p->prefixes), ms); -#ifdef XML_DTD - p->paramEntityRead = XML_FALSE; - hashTableInit(&(p->paramEntities), ms); -#endif /* XML_DTD */ - p->defaultPrefix.name = NULL; - p->defaultPrefix.binding = NULL; - - p->in_eldecl = XML_FALSE; - p->scaffIndex = NULL; - p->scaffold = NULL; - p->scaffLevel = 0; - p->scaffSize = 0; - p->scaffCount = 0; - p->contentStringLen = 0; - - p->keepProcessing = XML_TRUE; - p->hasParamEntityRefs = XML_FALSE; - p->standalone = XML_FALSE; - return p; -} - -static void -dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) -{ - HASH_TABLE_ITER iter; - hashTableIterInit(&iter, &(p->elementTypes)); - for (;;) { - ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); - if (!e) - break; - if (e->allocDefaultAtts != 0) - ms->free_fcn(e->defaultAtts); - } - hashTableClear(&(p->generalEntities)); -#ifdef XML_DTD - p->paramEntityRead = XML_FALSE; - hashTableClear(&(p->paramEntities)); -#endif /* XML_DTD */ - hashTableClear(&(p->elementTypes)); - hashTableClear(&(p->attributeIds)); - hashTableClear(&(p->prefixes)); - poolClear(&(p->pool)); - poolClear(&(p->entityValuePool)); - p->defaultPrefix.name = NULL; - p->defaultPrefix.binding = NULL; - - p->in_eldecl = XML_FALSE; - - ms->free_fcn(p->scaffIndex); - p->scaffIndex = NULL; - ms->free_fcn(p->scaffold); - p->scaffold = NULL; - - p->scaffLevel = 0; - p->scaffSize = 0; - p->scaffCount = 0; - p->contentStringLen = 0; - - p->keepProcessing = XML_TRUE; - p->hasParamEntityRefs = XML_FALSE; - p->standalone = XML_FALSE; -} - -static void -dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) -{ - HASH_TABLE_ITER iter; - hashTableIterInit(&iter, &(p->elementTypes)); - for (;;) { - ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); - if (!e) - break; - if (e->allocDefaultAtts != 0) - ms->free_fcn(e->defaultAtts); - } - hashTableDestroy(&(p->generalEntities)); -#ifdef XML_DTD - hashTableDestroy(&(p->paramEntities)); -#endif /* XML_DTD */ - hashTableDestroy(&(p->elementTypes)); - hashTableDestroy(&(p->attributeIds)); - hashTableDestroy(&(p->prefixes)); - poolDestroy(&(p->pool)); - poolDestroy(&(p->entityValuePool)); - if (isDocEntity) { - ms->free_fcn(p->scaffIndex); - ms->free_fcn(p->scaffold); - } - ms->free_fcn(p); -} - -/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise. - The new DTD has already been initialized. -*/ -static int -dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) -{ - HASH_TABLE_ITER iter; - - /* Copy the prefix table. */ - - hashTableIterInit(&iter, &(oldDtd->prefixes)); - for (;;) { - const XML_Char *name; - const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter); - if (!oldP) - break; - name = poolCopyString(&(newDtd->pool), oldP->name); - if (!name) - return 0; - if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX))) - return 0; - } - - hashTableIterInit(&iter, &(oldDtd->attributeIds)); - - /* Copy the attribute id table. */ - - for (;;) { - ATTRIBUTE_ID *newA; - const XML_Char *name; - const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter); - - if (!oldA) - break; - /* Remember to allocate the scratch byte before the name. */ - if (!poolAppendChar(&(newDtd->pool), XML_T('\0'))) - return 0; - name = poolCopyString(&(newDtd->pool), oldA->name); - if (!name) - return 0; - ++name; - newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name, - sizeof(ATTRIBUTE_ID)); - if (!newA) - return 0; - newA->maybeTokenized = oldA->maybeTokenized; - if (oldA->prefix) { - newA->xmlns = oldA->xmlns; - if (oldA->prefix == &oldDtd->defaultPrefix) - newA->prefix = &newDtd->defaultPrefix; - else - newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), - oldA->prefix->name, 0); - } - } - - /* Copy the element type table. */ - - hashTableIterInit(&iter, &(oldDtd->elementTypes)); - - for (;;) { - int i; - ELEMENT_TYPE *newE; - const XML_Char *name; - const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter); - if (!oldE) - break; - name = poolCopyString(&(newDtd->pool), oldE->name); - if (!name) - return 0; - newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name, - sizeof(ELEMENT_TYPE)); - if (!newE) - return 0; - if (oldE->nDefaultAtts) { - newE->defaultAtts = (DEFAULT_ATTRIBUTE *) - ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); - if (!newE->defaultAtts) { - ms->free_fcn(newE); - return 0; - } - } - if (oldE->idAtt) - newE->idAtt = (ATTRIBUTE_ID *) - lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0); - newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; - if (oldE->prefix) - newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), - oldE->prefix->name, 0); - for (i = 0; i < newE->nDefaultAtts; i++) { - newE->defaultAtts[i].id = (ATTRIBUTE_ID *) - lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); - newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; - if (oldE->defaultAtts[i].value) { - newE->defaultAtts[i].value - = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value); - if (!newE->defaultAtts[i].value) - return 0; - } - else - newE->defaultAtts[i].value = NULL; - } - } - - /* Copy the entity tables. */ - if (!copyEntityTable(oldParser, - &(newDtd->generalEntities), - &(newDtd->pool), - &(oldDtd->generalEntities))) - return 0; - -#ifdef XML_DTD - if (!copyEntityTable(oldParser, - &(newDtd->paramEntities), - &(newDtd->pool), - &(oldDtd->paramEntities))) - return 0; - newDtd->paramEntityRead = oldDtd->paramEntityRead; -#endif /* XML_DTD */ - - newDtd->keepProcessing = oldDtd->keepProcessing; - newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs; - newDtd->standalone = oldDtd->standalone; - - /* Don't want deep copying for scaffolding */ - newDtd->in_eldecl = oldDtd->in_eldecl; - newDtd->scaffold = oldDtd->scaffold; - newDtd->contentStringLen = oldDtd->contentStringLen; - newDtd->scaffSize = oldDtd->scaffSize; - newDtd->scaffLevel = oldDtd->scaffLevel; - newDtd->scaffIndex = oldDtd->scaffIndex; - - return 1; -} /* End dtdCopy */ - -static int -copyEntityTable(XML_Parser oldParser, - HASH_TABLE *newTable, - STRING_POOL *newPool, - const HASH_TABLE *oldTable) -{ - HASH_TABLE_ITER iter; - const XML_Char *cachedOldBase = NULL; - const XML_Char *cachedNewBase = NULL; - - hashTableIterInit(&iter, oldTable); - - for (;;) { - ENTITY *newE; - const XML_Char *name; - const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter); - if (!oldE) - break; - name = poolCopyString(newPool, oldE->name); - if (!name) - return 0; - newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY)); - if (!newE) - return 0; - if (oldE->systemId) { - const XML_Char *tem = poolCopyString(newPool, oldE->systemId); - if (!tem) - return 0; - newE->systemId = tem; - if (oldE->base) { - if (oldE->base == cachedOldBase) - newE->base = cachedNewBase; - else { - cachedOldBase = oldE->base; - tem = poolCopyString(newPool, cachedOldBase); - if (!tem) - return 0; - cachedNewBase = newE->base = tem; - } - } - if (oldE->publicId) { - tem = poolCopyString(newPool, oldE->publicId); - if (!tem) - return 0; - newE->publicId = tem; - } - } - else { - const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr, - oldE->textLen); - if (!tem) - return 0; - newE->textPtr = tem; - newE->textLen = oldE->textLen; - } - if (oldE->notation) { - const XML_Char *tem = poolCopyString(newPool, oldE->notation); - if (!tem) - return 0; - newE->notation = tem; - } - newE->is_param = oldE->is_param; - newE->is_internal = oldE->is_internal; - } - return 1; -} - -#define INIT_POWER 6 - -static XML_Bool FASTCALL -keyeq(KEY s1, KEY s2) -{ - for (; *s1 == *s2; s1++, s2++) - if (*s1 == 0) - return XML_TRUE; - return XML_FALSE; -} - -static unsigned long FASTCALL -hash(XML_Parser parser, KEY s) -{ - unsigned long h = hash_secret_salt; - while (*s) - h = CHAR_HASH(h, *s++); - return h; -} - -static NAMED * -lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize) -{ - size_t i; - if (table->size == 0) { - size_t tsize; - if (!createSize) - return NULL; - table->power = INIT_POWER; - /* table->size is a power of 2 */ - table->size = (size_t)1 << INIT_POWER; - tsize = table->size * sizeof(NAMED *); - table->v = (NAMED **)table->mem->malloc_fcn(tsize); - if (!table->v) { - table->size = 0; - return NULL; - } - memset(table->v, 0, tsize); - i = hash(parser, name) & ((unsigned long)table->size - 1); - } - else { - unsigned long h = hash(parser, name); - unsigned long mask = (unsigned long)table->size - 1; - unsigned char step = 0; - i = h & mask; - while (table->v[i]) { - if (keyeq(name, table->v[i]->name)) - return table->v[i]; - if (!step) - step = PROBE_STEP(h, mask, table->power); - i < step ? (i += table->size - step) : (i -= step); - } - if (!createSize) - return NULL; - - /* check for overflow (table is half full) */ - if (table->used >> (table->power - 1)) { - unsigned char newPower = table->power + 1; - size_t newSize = (size_t)1 << newPower; - unsigned long newMask = (unsigned long)newSize - 1; - size_t tsize = newSize * sizeof(NAMED *); - NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize); - if (!newV) - return NULL; - memset(newV, 0, tsize); - for (i = 0; i < table->size; i++) - if (table->v[i]) { - unsigned long newHash = hash(parser, table->v[i]->name); - size_t j = newHash & newMask; - step = 0; - while (newV[j]) { - if (!step) - step = PROBE_STEP(newHash, newMask, newPower); - j < step ? (j += newSize - step) : (j -= step); - } - newV[j] = table->v[i]; - } - table->mem->free_fcn(table->v); - table->v = newV; - table->power = newPower; - table->size = newSize; - i = h & newMask; - step = 0; - while (table->v[i]) { - if (!step) - step = PROBE_STEP(h, newMask, newPower); - i < step ? (i += newSize - step) : (i -= step); - } - } - } - table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize); - if (!table->v[i]) - return NULL; - memset(table->v[i], 0, createSize); - table->v[i]->name = name; - (table->used)++; - return table->v[i]; -} - -static void FASTCALL -hashTableClear(HASH_TABLE *table) -{ - size_t i; - for (i = 0; i < table->size; i++) { - table->mem->free_fcn(table->v[i]); - table->v[i] = NULL; - } - table->used = 0; -} - -static void FASTCALL -hashTableDestroy(HASH_TABLE *table) -{ - size_t i; - for (i = 0; i < table->size; i++) - table->mem->free_fcn(table->v[i]); - table->mem->free_fcn(table->v); -} - -static void FASTCALL -hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) -{ - p->power = 0; - p->size = 0; - p->used = 0; - p->v = NULL; - p->mem = ms; -} - -static void FASTCALL -hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) -{ - iter->p = table->v; - iter->end = iter->p + table->size; -} - -static NAMED * FASTCALL -hashTableIterNext(HASH_TABLE_ITER *iter) -{ - while (iter->p != iter->end) { - NAMED *tem = *(iter->p)++; - if (tem) - return tem; - } - return NULL; -} - -static void FASTCALL -poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms) -{ - pool->blocks = NULL; - pool->freeBlocks = NULL; - pool->start = NULL; - pool->ptr = NULL; - pool->end = NULL; - pool->mem = ms; -} - -static void FASTCALL -poolClear(STRING_POOL *pool) -{ - if (!pool->freeBlocks) - pool->freeBlocks = pool->blocks; - else { - BLOCK *p = pool->blocks; - while (p) { - BLOCK *tem = p->next; - p->next = pool->freeBlocks; - pool->freeBlocks = p; - p = tem; - } - } - pool->blocks = NULL; - pool->start = NULL; - pool->ptr = NULL; - pool->end = NULL; -} - -static void FASTCALL -poolDestroy(STRING_POOL *pool) -{ - BLOCK *p = pool->blocks; - while (p) { - BLOCK *tem = p->next; - pool->mem->free_fcn(p); - p = tem; - } - p = pool->freeBlocks; - while (p) { - BLOCK *tem = p->next; - pool->mem->free_fcn(p); - p = tem; - } -} - -static XML_Char * -poolAppend(STRING_POOL *pool, const ENCODING *enc, - const char *ptr, const char *end) -{ - if (!pool->ptr && !poolGrow(pool)) - return NULL; - for (;;) { - XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end); - if (ptr == end) - break; - if (!poolGrow(pool)) - return NULL; - } - return pool->start; -} - -static const XML_Char * FASTCALL -poolCopyString(STRING_POOL *pool, const XML_Char *s) -{ - do { - if (!poolAppendChar(pool, *s)) - return NULL; - } while (*s++); - s = pool->start; - poolFinish(pool); - return s; -} - -static const XML_Char * -poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) -{ - if (!pool->ptr && !poolGrow(pool)) - return NULL; - for (; n > 0; --n, s++) { - if (!poolAppendChar(pool, *s)) - return NULL; - } - s = pool->start; - poolFinish(pool); - return s; -} - -static const XML_Char * FASTCALL -poolAppendString(STRING_POOL *pool, const XML_Char *s) -{ - while (*s) { - if (!poolAppendChar(pool, *s)) - return NULL; - s++; - } - return pool->start; -} - -static XML_Char * -poolStoreString(STRING_POOL *pool, const ENCODING *enc, - const char *ptr, const char *end) -{ - if (!poolAppend(pool, enc, ptr, end)) - return NULL; - if (pool->ptr == pool->end && !poolGrow(pool)) - return NULL; - *(pool->ptr)++ = 0; - return pool->start; -} - -static XML_Bool FASTCALL -poolGrow(STRING_POOL *pool) -{ - if (pool->freeBlocks) { - if (pool->start == 0) { - pool->blocks = pool->freeBlocks; - pool->freeBlocks = pool->freeBlocks->next; - pool->blocks->next = NULL; - pool->start = pool->blocks->s; - pool->end = pool->start + pool->blocks->size; - pool->ptr = pool->start; - return XML_TRUE; - } - if (pool->end - pool->start < pool->freeBlocks->size) { - BLOCK *tem = pool->freeBlocks->next; - pool->freeBlocks->next = pool->blocks; - pool->blocks = pool->freeBlocks; - pool->freeBlocks = tem; - memcpy(pool->blocks->s, pool->start, - (pool->end - pool->start) * sizeof(XML_Char)); - pool->ptr = pool->blocks->s + (pool->ptr - pool->start); - pool->start = pool->blocks->s; - pool->end = pool->start + pool->blocks->size; - return XML_TRUE; - } - } - if (pool->blocks && pool->start == pool->blocks->s) { - int blockSize = (int)(pool->end - pool->start)*2; - BLOCK *temp = (BLOCK *) - pool->mem->realloc_fcn(pool->blocks, - (offsetof(BLOCK, s) - + blockSize * sizeof(XML_Char))); - if (temp == NULL) - return XML_FALSE; - pool->blocks = temp; - pool->blocks->size = blockSize; - pool->ptr = pool->blocks->s + (pool->ptr - pool->start); - pool->start = pool->blocks->s; - pool->end = pool->start + blockSize; - } - else { - BLOCK *tem; - int blockSize = (int)(pool->end - pool->start); - if (blockSize < INIT_BLOCK_SIZE) - blockSize = INIT_BLOCK_SIZE; - else - blockSize *= 2; - tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s) - + blockSize * sizeof(XML_Char)); - if (!tem) - return XML_FALSE; - tem->size = blockSize; - tem->next = pool->blocks; - pool->blocks = tem; - if (pool->ptr != pool->start) - memcpy(tem->s, pool->start, - (pool->ptr - pool->start) * sizeof(XML_Char)); - pool->ptr = tem->s + (pool->ptr - pool->start); - pool->start = tem->s; - pool->end = tem->s + blockSize; - } - return XML_TRUE; -} - -static int FASTCALL -nextScaffoldPart(XML_Parser parser) -{ - DTD * const dtd = _dtd; /* save one level of indirection */ - CONTENT_SCAFFOLD * me; - int next; - - if (!dtd->scaffIndex) { - dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int)); - if (!dtd->scaffIndex) - return -1; - dtd->scaffIndex[0] = 0; - } - - if (dtd->scaffCount >= dtd->scaffSize) { - CONTENT_SCAFFOLD *temp; - if (dtd->scaffold) { - temp = (CONTENT_SCAFFOLD *) - REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); - if (temp == NULL) - return -1; - dtd->scaffSize *= 2; - } - else { - temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS - * sizeof(CONTENT_SCAFFOLD)); - if (temp == NULL) - return -1; - dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS; - } - dtd->scaffold = temp; - } - next = dtd->scaffCount++; - me = &dtd->scaffold[next]; - if (dtd->scaffLevel) { - CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]]; - if (parent->lastchild) { - dtd->scaffold[parent->lastchild].nextsib = next; - } - if (!parent->childcnt) - parent->firstchild = next; - parent->lastchild = next; - parent->childcnt++; - } - me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0; - return next; -} - -static void -build_node(XML_Parser parser, - int src_node, - XML_Content *dest, - XML_Content **contpos, - XML_Char **strpos) -{ - DTD * const dtd = _dtd; /* save one level of indirection */ - dest->type = dtd->scaffold[src_node].type; - dest->quant = dtd->scaffold[src_node].quant; - if (dest->type == XML_CTYPE_NAME) { - const XML_Char *src; - dest->name = *strpos; - src = dtd->scaffold[src_node].name; - for (;;) { - *(*strpos)++ = *src; - if (!*src) - break; - src++; - } - dest->numchildren = 0; - dest->children = NULL; - } - else { - unsigned int i; - int cn; - dest->numchildren = dtd->scaffold[src_node].childcnt; - dest->children = *contpos; - *contpos += dest->numchildren; - for (i = 0, cn = dtd->scaffold[src_node].firstchild; - i < dest->numchildren; - i++, cn = dtd->scaffold[cn].nextsib) { - build_node(parser, cn, &(dest->children[i]), contpos, strpos); - } - dest->name = NULL; - } -} - -static XML_Content * -build_model (XML_Parser parser) -{ - DTD * const dtd = _dtd; /* save one level of indirection */ - XML_Content *ret; - XML_Content *cpos; - XML_Char * str; - int allocsize = (dtd->scaffCount * sizeof(XML_Content) - + (dtd->contentStringLen * sizeof(XML_Char))); - - ret = (XML_Content *)MALLOC(allocsize); - if (!ret) - return NULL; - - str = (XML_Char *) (&ret[dtd->scaffCount]); - cpos = &ret[1]; - - build_node(parser, 0, ret, &cpos, &str); - return ret; -} - -static ELEMENT_TYPE * -getElementType(XML_Parser parser, - const ENCODING *enc, - const char *ptr, - const char *end) -{ - DTD * const dtd = _dtd; /* save one level of indirection */ - const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end); - ELEMENT_TYPE *ret; - - if (!name) - return NULL; - ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); - if (!ret) - return NULL; - if (ret->name != name) - poolDiscard(&dtd->pool); - else { - poolFinish(&dtd->pool); - if (!setElementTypePrefix(parser, ret)) - return NULL; - } - return ret; -} diff -Nru simgear-2.10.0/simgear/xml/xmlparse.h simgear-3.0.0/simgear/xml/xmlparse.h --- simgear-2.10.0/simgear/xml/xmlparse.h 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/xml/xmlparse.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,482 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (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.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -#ifndef XmlParse_INCLUDED -#define XmlParse_INCLUDED 1 - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef XMLPARSEAPI -#define XMLPARSEAPI /* as nothing */ -#endif - -typedef void *XML_Parser; - -#ifdef XML_UNICODE_WCHAR_T - -/* XML_UNICODE_WCHAR_T will work only if sizeof(wchar_t) == 2 and wchar_t -uses Unicode. */ -/* Information is UTF-16 encoded as wchar_ts */ - -#ifndef XML_UNICODE -#define XML_UNICODE -#endif - -#include -typedef wchar_t XML_Char; -typedef wchar_t XML_LChar; - -#else /* not XML_UNICODE_WCHAR_T */ - -#ifdef XML_UNICODE - -/* Information is UTF-16 encoded as unsigned shorts */ -typedef unsigned short XML_Char; -typedef char XML_LChar; - -#else /* not XML_UNICODE */ - -/* Information is UTF-8 encoded. */ -typedef char XML_Char; -typedef char XML_LChar; - -#endif /* not XML_UNICODE */ - -#endif /* not XML_UNICODE_WCHAR_T */ - - -/* Constructs a new parser; encoding is the encoding specified by the external -protocol or null if there is none specified. */ - -XML_Parser XMLPARSEAPI -XML_ParserCreate(const XML_Char *encoding); - -/* Constructs a new parser and namespace processor. Element type names -and attribute names that belong to a namespace will be expanded; -unprefixed attribute names are never expanded; unprefixed element type -names are expanded only if there is a default namespace. The expanded -name is the concatenation of the namespace URI, the namespace separator character, -and the local part of the name. If the namespace separator is '\0' then -the namespace URI and the local part will be concatenated without any -separator. When a namespace is not declared, the name and prefix will be -passed through without expansion. */ - -XML_Parser XMLPARSEAPI -XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); - - -/* atts is array of name/value pairs, terminated by 0; - names and values are 0 terminated. */ - -typedef void (*XML_StartElementHandler)(void *userData, - const XML_Char *name, - const XML_Char **atts); - -typedef void (*XML_EndElementHandler)(void *userData, - const XML_Char *name); - -/* s is not 0 terminated. */ -typedef void (*XML_CharacterDataHandler)(void *userData, - const XML_Char *s, - int len); - -/* target and data are 0 terminated */ -typedef void (*XML_ProcessingInstructionHandler)(void *userData, - const XML_Char *target, - const XML_Char *data); - -/* data is 0 terminated */ -typedef void (*XML_CommentHandler)(void *userData, const XML_Char *data); - -typedef void (*XML_StartCdataSectionHandler)(void *userData); -typedef void (*XML_EndCdataSectionHandler)(void *userData); - -/* This is called for any characters in the XML document for -which there is no applicable handler. This includes both -characters that are part of markup which is of a kind that is -not reported (comments, markup declarations), or characters -that are part of a construct which could be reported but -for which no handler has been supplied. The characters are passed -exactly as they were in the XML document except that -they will be encoded in UTF-8. Line boundaries are not normalized. -Note that a byte order mark character is not passed to the default handler. -There are no guarantees about how characters are divided between calls -to the default handler: for example, a comment might be split between -multiple calls. */ - -typedef void (*XML_DefaultHandler)(void *userData, - const XML_Char *s, - int len); - -/* This is called for a declaration of an unparsed (NDATA) -entity. The base argument is whatever was set by XML_SetBase. -The entityName, systemId and notationName arguments will never be null. -The other arguments may be. */ - -typedef void (*XML_UnparsedEntityDeclHandler)(void *userData, - const XML_Char *entityName, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId, - const XML_Char *notationName); - -/* This is called for a declaration of notation. -The base argument is whatever was set by XML_SetBase. -The notationName will never be null. The other arguments can be. */ - -typedef void (*XML_NotationDeclHandler)(void *userData, - const XML_Char *notationName, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId); - -/* When namespace processing is enabled, these are called once for -each namespace declaration. The call to the start and end element -handlers occur between the calls to the start and end namespace -declaration handlers. For an xmlns attribute, prefix will be null. -For an xmlns="" attribute, uri will be null. */ - -typedef void (*XML_StartNamespaceDeclHandler)(void *userData, - const XML_Char *prefix, - const XML_Char *uri); - -typedef void (*XML_EndNamespaceDeclHandler)(void *userData, - const XML_Char *prefix); - -/* This is called if the document is not standalone (it has an -external subset or a reference to a parameter entity, but does not -have standalone="yes"). If this handler returns 0, then processing -will not continue, and the parser will return a -XML_ERROR_NOT_STANDALONE error. */ - -typedef int (*XML_NotStandaloneHandler)(void *userData); - -/* This is called for a reference to an external parsed general entity. -The referenced entity is not automatically parsed. -The application can parse it immediately or later using -XML_ExternalEntityParserCreate. -The parser argument is the parser parsing the entity containing the reference; -it can be passed as the parser argument to XML_ExternalEntityParserCreate. -The systemId argument is the system identifier as specified in the entity declaration; -it will not be null. -The base argument is the system identifier that should be used as the base for -resolving systemId if systemId was relative; this is set by XML_SetBase; -it may be null. -The publicId argument is the public identifier as specified in the entity declaration, -or null if none was specified; the whitespace in the public identifier -will have been normalized as required by the XML spec. -The context argument specifies the parsing context in the format -expected by the context argument to -XML_ExternalEntityParserCreate; context is valid only until the handler -returns, so if the referenced entity is to be parsed later, it must be copied. -The handler should return 0 if processing should not continue because of -a fatal error in the handling of the external entity. -In this case the calling parser will return an XML_ERROR_EXTERNAL_ENTITY_HANDLING -error. -Note that unlike other handlers the first argument is the parser, not userData. */ - -typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser, - const XML_Char *context, - const XML_Char *base, - const XML_Char *systemId, - const XML_Char *publicId); - -/* This structure is filled in by the XML_UnknownEncodingHandler -to provide information to the parser about encodings that are unknown -to the parser. -The map[b] member gives information about byte sequences -whose first byte is b. -If map[b] is c where c is >= 0, then b by itself encodes the Unicode scalar value c. -If map[b] is -1, then the byte sequence is malformed. -If map[b] is -n, where n >= 2, then b is the first byte of an n-byte -sequence that encodes a single Unicode scalar value. -The data member will be passed as the first argument to the convert function. -The convert function is used to convert multibyte sequences; -s will point to a n-byte sequence where map[(unsigned char)*s] == -n. -The convert function must return the Unicode scalar value -represented by this byte sequence or -1 if the byte sequence is malformed. -The convert function may be null if the encoding is a single-byte encoding, -that is if map[b] >= -1 for all bytes b. -When the parser is finished with the encoding, then if release is not null, -it will call release passing it the data member; -once release has been called, the convert function will not be called again. - -Expat places certain restrictions on the encodings that are supported -using this mechanism. - -1. Every ASCII character that can appear in a well-formed XML document, -other than the characters - - $@\^`{}~ - -must be represented by a single byte, and that byte must be the -same byte that represents that character in ASCII. - -2. No character may require more than 4 bytes to encode. - -3. All characters encoded must have Unicode scalar values <= 0xFFFF, -(ie characters that would be encoded by surrogates in UTF-16 -are not allowed). Note that this restriction doesn't apply to -the built-in support for UTF-8 and UTF-16. - -4. No Unicode character may be encoded by more than one distinct sequence -of bytes. */ - -typedef struct { - int map[256]; - void *data; - int (*convert)(void *data, const char *s); - void (*release)(void *data); -} XML_Encoding; - -/* This is called for an encoding that is unknown to the parser. -The encodingHandlerData argument is that which was passed as the -second argument to XML_SetUnknownEncodingHandler. -The name argument gives the name of the encoding as specified in -the encoding declaration. -If the callback can provide information about the encoding, -it must fill in the XML_Encoding structure, and return 1. -Otherwise it must return 0. -If info does not describe a suitable encoding, -then the parser will return an XML_UNKNOWN_ENCODING error. */ - -typedef int (*XML_UnknownEncodingHandler)(void *encodingHandlerData, - const XML_Char *name, - XML_Encoding *info); - -void XMLPARSEAPI -XML_SetElementHandler(XML_Parser parser, - XML_StartElementHandler start, - XML_EndElementHandler end); - -void XMLPARSEAPI -XML_SetCharacterDataHandler(XML_Parser parser, - XML_CharacterDataHandler handler); - -void XMLPARSEAPI -XML_SetProcessingInstructionHandler(XML_Parser parser, - XML_ProcessingInstructionHandler handler); -void XMLPARSEAPI -XML_SetCommentHandler(XML_Parser parser, - XML_CommentHandler handler); - -void XMLPARSEAPI -XML_SetCdataSectionHandler(XML_Parser parser, - XML_StartCdataSectionHandler start, - XML_EndCdataSectionHandler end); - -/* This sets the default handler and also inhibits expansion of internal entities. -The entity reference will be passed to the default handler. */ - -void XMLPARSEAPI -XML_SetDefaultHandler(XML_Parser parser, - XML_DefaultHandler handler); - -/* This sets the default handler but does not inhibit expansion of internal entities. -The entity reference will not be passed to the default handler. */ - -void XMLPARSEAPI -XML_SetDefaultHandlerExpand(XML_Parser parser, - XML_DefaultHandler handler); - -void XMLPARSEAPI -XML_SetUnparsedEntityDeclHandler(XML_Parser parser, - XML_UnparsedEntityDeclHandler handler); - -void XMLPARSEAPI -XML_SetNotationDeclHandler(XML_Parser parser, - XML_NotationDeclHandler handler); - -void XMLPARSEAPI -XML_SetNamespaceDeclHandler(XML_Parser parser, - XML_StartNamespaceDeclHandler start, - XML_EndNamespaceDeclHandler end); - -void XMLPARSEAPI -XML_SetNotStandaloneHandler(XML_Parser parser, - XML_NotStandaloneHandler handler); - -void XMLPARSEAPI -XML_SetExternalEntityRefHandler(XML_Parser parser, - XML_ExternalEntityRefHandler handler); - -/* If a non-null value for arg is specified here, then it will be passed -as the first argument to the external entity ref handler instead -of the parser object. */ -void XMLPARSEAPI -XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg); - -void XMLPARSEAPI -XML_SetUnknownEncodingHandler(XML_Parser parser, - XML_UnknownEncodingHandler handler, - void *encodingHandlerData); - -/* This can be called within a handler for a start element, end element, -processing instruction or character data. It causes the corresponding -markup to be passed to the default handler. */ -void XMLPARSEAPI XML_DefaultCurrent(XML_Parser parser); - -/* This value is passed as the userData argument to callbacks. */ -void XMLPARSEAPI -XML_SetUserData(XML_Parser parser, void *userData); - -/* Returns the last value set by XML_SetUserData or null. */ -#define XML_GetUserData(parser) (*(void **)(parser)) - -/* This is equivalent to supplying an encoding argument -to XML_CreateParser. It must not be called after XML_Parse -or XML_ParseBuffer. */ - -int XMLPARSEAPI -XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); - -/* If this function is called, then the parser will be passed -as the first argument to callbacks instead of userData. -The userData will still be accessible using XML_GetUserData. */ - -void XMLPARSEAPI -XML_UseParserAsHandlerArg(XML_Parser parser); - -/* Sets the base to be used for resolving relative URIs in system identifiers in -declarations. Resolving relative identifiers is left to the application: -this value will be passed through as the base argument to the -XML_ExternalEntityRefHandler, XML_NotationDeclHandler -and XML_UnparsedEntityDeclHandler. The base argument will be copied. -Returns zero if out of memory, non-zero otherwise. */ - -int XMLPARSEAPI -XML_SetBase(XML_Parser parser, const XML_Char *base); - -const XML_Char XMLPARSEAPI * -XML_GetBase(XML_Parser parser); - -/* Returns the number of the attributes passed in last call to the -XML_StartElementHandler that were specified in the start-tag rather -than defaulted. */ - -int XMLPARSEAPI XML_GetSpecifiedAttributeCount(XML_Parser parser); - -/* Parses some input. Returns 0 if a fatal error is detected. -The last call to XML_Parse must have isFinal true; -len may be zero for this call (or any other). */ -int XMLPARSEAPI -XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); - -void XMLPARSEAPI * -XML_GetBuffer(XML_Parser parser, int len); - -int XMLPARSEAPI -XML_ParseBuffer(XML_Parser parser, int len, int isFinal); - -/* Creates an XML_Parser object that can parse an external general entity; -context is a '\0'-terminated string specifying the parse context; -encoding is a '\0'-terminated string giving the name of the externally specified encoding, -or null if there is no externally specified encoding. -The context string consists of a sequence of tokens separated by formfeeds (\f); -a token consisting of a name specifies that the general entity of the name -is open; a token of the form prefix=uri specifies the namespace for a particular -prefix; a token of the form =uri specifies the default namespace. -This can be called at any point after the first call to an ExternalEntityRefHandler -so longer as the parser has not yet been freed. -The new parser is completely independent and may safely be used in a separate thread. -The handlers and userData are initialized from the parser argument. -Returns 0 if out of memory. Otherwise returns a new XML_Parser object. */ -XML_Parser XMLPARSEAPI -XML_ExternalEntityParserCreate(XML_Parser parser, - const XML_Char *context, - const XML_Char *encoding); - -enum XML_Error { - XML_ERROR_NONE, - XML_ERROR_NO_MEMORY, - XML_ERROR_SYNTAX, - XML_ERROR_NO_ELEMENTS, - XML_ERROR_INVALID_TOKEN, - XML_ERROR_UNCLOSED_TOKEN, - XML_ERROR_PARTIAL_CHAR, - XML_ERROR_TAG_MISMATCH, - XML_ERROR_DUPLICATE_ATTRIBUTE, - XML_ERROR_JUNK_AFTER_DOC_ELEMENT, - XML_ERROR_PARAM_ENTITY_REF, - XML_ERROR_UNDEFINED_ENTITY, - XML_ERROR_RECURSIVE_ENTITY_REF, - XML_ERROR_ASYNC_ENTITY, - XML_ERROR_BAD_CHAR_REF, - XML_ERROR_BINARY_ENTITY_REF, - XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, - XML_ERROR_MISPLACED_XML_PI, - XML_ERROR_UNKNOWN_ENCODING, - XML_ERROR_INCORRECT_ENCODING, - XML_ERROR_UNCLOSED_CDATA_SECTION, - XML_ERROR_EXTERNAL_ENTITY_HANDLING, - XML_ERROR_NOT_STANDALONE -}; - -/* If XML_Parse or XML_ParseBuffer have returned 0, then XML_GetErrorCode -returns information about the error. */ - -enum XML_Error XMLPARSEAPI XML_GetErrorCode(XML_Parser parser); - -/* These functions return information about the current parse location. -They may be called when XML_Parse or XML_ParseBuffer return 0; -in this case the location is the location of the character at which -the error was detected. -They may also be called from any other callback called to report -some parse event; in this the location is the location of the first -of the sequence of characters that generated the event. */ - -int XMLPARSEAPI XML_GetCurrentLineNumber(XML_Parser parser); -int XMLPARSEAPI XML_GetCurrentColumnNumber(XML_Parser parser); -long XMLPARSEAPI XML_GetCurrentByteIndex(XML_Parser parser); - -/* Return the number of bytes in the current event. -Returns 0 if the event is in an internal entity. */ - -int XMLPARSEAPI XML_GetCurrentByteCount(XML_Parser parser); - -/* For backwards compatibility with previous versions. */ -#define XML_GetErrorLineNumber XML_GetCurrentLineNumber -#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber -#define XML_GetErrorByteIndex XML_GetCurrentByteIndex - -/* Frees memory used by the parser. */ -void XMLPARSEAPI -XML_ParserFree(XML_Parser parser); - -/* Returns a string describing the error. */ -const XML_LChar XMLPARSEAPI *XML_ErrorString(int code); - -#ifdef __cplusplus -} -#endif - -#endif /* not XmlParse_INCLUDED */ diff -Nru simgear-2.10.0/simgear/xml/xmlrole.c simgear-3.0.0/simgear/xml/xmlrole.c --- simgear-2.10.0/simgear/xml/xmlrole.c 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/xmlrole.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1336 +0,0 @@ -/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd - See the file COPYING for copying permission. -*/ - -#include - -#ifdef COMPILED_FROM_DSP -#include "winconfig.h" -#elif defined(MACOS_CLASSIC) -#include "macconfig.h" -#elif defined(__amigaos__) -#include "amigaconfig.h" -#elif defined(__WATCOMC__) -#include "watcomconfig.h" -#else -#ifdef HAVE_EXPAT_CONFIG_H -#include "expat_config.h" -#endif -#endif /* ndef COMPILED_FROM_DSP */ - -#include "expat_external.h" -#include "internal.h" -#include "xmlrole.h" -#include "ascii.h" - -/* Doesn't check: - - that ,| are not mixed in a model group - content of literals - -*/ - -static const char KW_ANY[] = { - ASCII_A, ASCII_N, ASCII_Y, '\0' }; -static const char KW_ATTLIST[] = { - ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' }; -static const char KW_CDATA[] = { - ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; -static const char KW_DOCTYPE[] = { - ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' }; -static const char KW_ELEMENT[] = { - ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' }; -static const char KW_EMPTY[] = { - ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' }; -static const char KW_ENTITIES[] = { - ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, - '\0' }; -static const char KW_ENTITY[] = { - ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' }; -static const char KW_FIXED[] = { - ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' }; -static const char KW_ID[] = { - ASCII_I, ASCII_D, '\0' }; -static const char KW_IDREF[] = { - ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' }; -static const char KW_IDREFS[] = { - ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' }; -#ifdef XML_DTD -static const char KW_IGNORE[] = { - ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' }; -#endif -static const char KW_IMPLIED[] = { - ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' }; -#ifdef XML_DTD -static const char KW_INCLUDE[] = { - ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' }; -#endif -static const char KW_NDATA[] = { - ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; -static const char KW_NMTOKEN[] = { - ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' }; -static const char KW_NMTOKENS[] = { - ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, - '\0' }; -static const char KW_NOTATION[] = - { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, - '\0' }; -static const char KW_PCDATA[] = { - ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; -static const char KW_PUBLIC[] = { - ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' }; -static const char KW_REQUIRED[] = { - ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D, - '\0' }; -static const char KW_SYSTEM[] = { - ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' }; - -#ifndef MIN_BYTES_PER_CHAR -#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar) -#endif - -#ifdef XML_DTD -#define setTopLevel(state) \ - ((state)->handler = ((state)->documentEntity \ - ? internalSubset \ - : externalSubset1)) -#else /* not XML_DTD */ -#define setTopLevel(state) ((state)->handler = internalSubset) -#endif /* not XML_DTD */ - -typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc); - -static PROLOG_HANDLER - prolog0, prolog1, prolog2, - doctype0, doctype1, doctype2, doctype3, doctype4, doctype5, - internalSubset, - entity0, entity1, entity2, entity3, entity4, entity5, entity6, - entity7, entity8, entity9, entity10, - notation0, notation1, notation2, notation3, notation4, - attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6, - attlist7, attlist8, attlist9, - element0, element1, element2, element3, element4, element5, element6, - element7, -#ifdef XML_DTD - externalSubset0, externalSubset1, - condSect0, condSect1, condSect2, -#endif /* XML_DTD */ - declClose, - error; - -static int FASTCALL common(PROLOG_STATE *state, int tok); - -static int PTRCALL -prolog0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - state->handler = prolog1; - return XML_ROLE_NONE; - case XML_TOK_XML_DECL: - state->handler = prolog1; - return XML_ROLE_XML_DECL; - case XML_TOK_PI: - state->handler = prolog1; - return XML_ROLE_PI; - case XML_TOK_COMMENT: - state->handler = prolog1; - return XML_ROLE_COMMENT; - case XML_TOK_BOM: - return XML_ROLE_NONE; - case XML_TOK_DECL_OPEN: - if (!XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - end, - KW_DOCTYPE)) - break; - state->handler = doctype0; - return XML_ROLE_DOCTYPE_NONE; - case XML_TOK_INSTANCE_START: - state->handler = error; - return XML_ROLE_INSTANCE_START; - } - return common(state, tok); -} - -static int PTRCALL -prolog1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_PI: - return XML_ROLE_PI; - case XML_TOK_COMMENT: - return XML_ROLE_COMMENT; - case XML_TOK_BOM: - return XML_ROLE_NONE; - case XML_TOK_DECL_OPEN: - if (!XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - end, - KW_DOCTYPE)) - break; - state->handler = doctype0; - return XML_ROLE_DOCTYPE_NONE; - case XML_TOK_INSTANCE_START: - state->handler = error; - return XML_ROLE_INSTANCE_START; - } - return common(state, tok); -} - -static int PTRCALL -prolog2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_PI: - return XML_ROLE_PI; - case XML_TOK_COMMENT: - return XML_ROLE_COMMENT; - case XML_TOK_INSTANCE_START: - state->handler = error; - return XML_ROLE_INSTANCE_START; - } - return common(state, tok); -} - -static int PTRCALL -doctype0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_DOCTYPE_NONE; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = doctype1; - return XML_ROLE_DOCTYPE_NAME; - } - return common(state, tok); -} - -static int PTRCALL -doctype1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_DOCTYPE_NONE; - case XML_TOK_OPEN_BRACKET: - state->handler = internalSubset; - return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; - case XML_TOK_DECL_CLOSE: - state->handler = prolog2; - return XML_ROLE_DOCTYPE_CLOSE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { - state->handler = doctype3; - return XML_ROLE_DOCTYPE_NONE; - } - if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { - state->handler = doctype2; - return XML_ROLE_DOCTYPE_NONE; - } - break; - } - return common(state, tok); -} - -static int PTRCALL -doctype2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_DOCTYPE_NONE; - case XML_TOK_LITERAL: - state->handler = doctype3; - return XML_ROLE_DOCTYPE_PUBLIC_ID; - } - return common(state, tok); -} - -static int PTRCALL -doctype3(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_DOCTYPE_NONE; - case XML_TOK_LITERAL: - state->handler = doctype4; - return XML_ROLE_DOCTYPE_SYSTEM_ID; - } - return common(state, tok); -} - -static int PTRCALL -doctype4(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_DOCTYPE_NONE; - case XML_TOK_OPEN_BRACKET: - state->handler = internalSubset; - return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; - case XML_TOK_DECL_CLOSE: - state->handler = prolog2; - return XML_ROLE_DOCTYPE_CLOSE; - } - return common(state, tok); -} - -static int PTRCALL -doctype5(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_DOCTYPE_NONE; - case XML_TOK_DECL_CLOSE: - state->handler = prolog2; - return XML_ROLE_DOCTYPE_CLOSE; - } - return common(state, tok); -} - -static int PTRCALL -internalSubset(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_DECL_OPEN: - if (XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - end, - KW_ENTITY)) { - state->handler = entity0; - return XML_ROLE_ENTITY_NONE; - } - if (XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - end, - KW_ATTLIST)) { - state->handler = attlist0; - return XML_ROLE_ATTLIST_NONE; - } - if (XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - end, - KW_ELEMENT)) { - state->handler = element0; - return XML_ROLE_ELEMENT_NONE; - } - if (XmlNameMatchesAscii(enc, - ptr + 2 * MIN_BYTES_PER_CHAR(enc), - end, - KW_NOTATION)) { - state->handler = notation0; - return XML_ROLE_NOTATION_NONE; - } - break; - case XML_TOK_PI: - return XML_ROLE_PI; - case XML_TOK_COMMENT: - return XML_ROLE_COMMENT; - case XML_TOK_PARAM_ENTITY_REF: - return XML_ROLE_PARAM_ENTITY_REF; - case XML_TOK_CLOSE_BRACKET: - state->handler = doctype5; - return XML_ROLE_DOCTYPE_NONE; - case XML_TOK_NONE: - return XML_ROLE_NONE; - } - return common(state, tok); -} - -#ifdef XML_DTD - -static int PTRCALL -externalSubset0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - state->handler = externalSubset1; - if (tok == XML_TOK_XML_DECL) - return XML_ROLE_TEXT_DECL; - return externalSubset1(state, tok, ptr, end, enc); -} - -static int PTRCALL -externalSubset1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_COND_SECT_OPEN: - state->handler = condSect0; - return XML_ROLE_NONE; - case XML_TOK_COND_SECT_CLOSE: - if (state->includeLevel == 0) - break; - state->includeLevel -= 1; - return XML_ROLE_NONE; - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_CLOSE_BRACKET: - break; - case XML_TOK_NONE: - if (state->includeLevel) - break; - return XML_ROLE_NONE; - default: - return internalSubset(state, tok, ptr, end, enc); - } - return common(state, tok); -} - -#endif /* XML_DTD */ - -static int PTRCALL -entity0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ENTITY_NONE; - case XML_TOK_PERCENT: - state->handler = entity1; - return XML_ROLE_ENTITY_NONE; - case XML_TOK_NAME: - state->handler = entity2; - return XML_ROLE_GENERAL_ENTITY_NAME; - } - return common(state, tok); -} - -static int PTRCALL -entity1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ENTITY_NONE; - case XML_TOK_NAME: - state->handler = entity7; - return XML_ROLE_PARAM_ENTITY_NAME; - } - return common(state, tok); -} - -static int PTRCALL -entity2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ENTITY_NONE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { - state->handler = entity4; - return XML_ROLE_ENTITY_NONE; - } - if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { - state->handler = entity3; - return XML_ROLE_ENTITY_NONE; - } - break; - case XML_TOK_LITERAL: - state->handler = declClose; - state->role_none = XML_ROLE_ENTITY_NONE; - return XML_ROLE_ENTITY_VALUE; - } - return common(state, tok); -} - -static int PTRCALL -entity3(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ENTITY_NONE; - case XML_TOK_LITERAL: - state->handler = entity4; - return XML_ROLE_ENTITY_PUBLIC_ID; - } - return common(state, tok); -} - -static int PTRCALL -entity4(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ENTITY_NONE; - case XML_TOK_LITERAL: - state->handler = entity5; - return XML_ROLE_ENTITY_SYSTEM_ID; - } - return common(state, tok); -} - -static int PTRCALL -entity5(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ENTITY_NONE; - case XML_TOK_DECL_CLOSE: - setTopLevel(state); - return XML_ROLE_ENTITY_COMPLETE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) { - state->handler = entity6; - return XML_ROLE_ENTITY_NONE; - } - break; - } - return common(state, tok); -} - -static int PTRCALL -entity6(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ENTITY_NONE; - case XML_TOK_NAME: - state->handler = declClose; - state->role_none = XML_ROLE_ENTITY_NONE; - return XML_ROLE_ENTITY_NOTATION_NAME; - } - return common(state, tok); -} - -static int PTRCALL -entity7(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ENTITY_NONE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { - state->handler = entity9; - return XML_ROLE_ENTITY_NONE; - } - if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { - state->handler = entity8; - return XML_ROLE_ENTITY_NONE; - } - break; - case XML_TOK_LITERAL: - state->handler = declClose; - state->role_none = XML_ROLE_ENTITY_NONE; - return XML_ROLE_ENTITY_VALUE; - } - return common(state, tok); -} - -static int PTRCALL -entity8(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ENTITY_NONE; - case XML_TOK_LITERAL: - state->handler = entity9; - return XML_ROLE_ENTITY_PUBLIC_ID; - } - return common(state, tok); -} - -static int PTRCALL -entity9(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ENTITY_NONE; - case XML_TOK_LITERAL: - state->handler = entity10; - return XML_ROLE_ENTITY_SYSTEM_ID; - } - return common(state, tok); -} - -static int PTRCALL -entity10(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ENTITY_NONE; - case XML_TOK_DECL_CLOSE: - setTopLevel(state); - return XML_ROLE_ENTITY_COMPLETE; - } - return common(state, tok); -} - -static int PTRCALL -notation0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NOTATION_NONE; - case XML_TOK_NAME: - state->handler = notation1; - return XML_ROLE_NOTATION_NAME; - } - return common(state, tok); -} - -static int PTRCALL -notation1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NOTATION_NONE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { - state->handler = notation3; - return XML_ROLE_NOTATION_NONE; - } - if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { - state->handler = notation2; - return XML_ROLE_NOTATION_NONE; - } - break; - } - return common(state, tok); -} - -static int PTRCALL -notation2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NOTATION_NONE; - case XML_TOK_LITERAL: - state->handler = notation4; - return XML_ROLE_NOTATION_PUBLIC_ID; - } - return common(state, tok); -} - -static int PTRCALL -notation3(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NOTATION_NONE; - case XML_TOK_LITERAL: - state->handler = declClose; - state->role_none = XML_ROLE_NOTATION_NONE; - return XML_ROLE_NOTATION_SYSTEM_ID; - } - return common(state, tok); -} - -static int PTRCALL -notation4(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NOTATION_NONE; - case XML_TOK_LITERAL: - state->handler = declClose; - state->role_none = XML_ROLE_NOTATION_NONE; - return XML_ROLE_NOTATION_SYSTEM_ID; - case XML_TOK_DECL_CLOSE: - setTopLevel(state); - return XML_ROLE_NOTATION_NO_SYSTEM_ID; - } - return common(state, tok); -} - -static int PTRCALL -attlist0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = attlist1; - return XML_ROLE_ATTLIST_ELEMENT_NAME; - } - return common(state, tok); -} - -static int PTRCALL -attlist1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_DECL_CLOSE: - setTopLevel(state); - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = attlist2; - return XML_ROLE_ATTRIBUTE_NAME; - } - return common(state, tok); -} - -static int PTRCALL -attlist2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_NAME: - { - static const char * const types[] = { - KW_CDATA, - KW_ID, - KW_IDREF, - KW_IDREFS, - KW_ENTITY, - KW_ENTITIES, - KW_NMTOKEN, - KW_NMTOKENS, - }; - int i; - for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++) - if (XmlNameMatchesAscii(enc, ptr, end, types[i])) { - state->handler = attlist8; - return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i; - } - } - if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) { - state->handler = attlist5; - return XML_ROLE_ATTLIST_NONE; - } - break; - case XML_TOK_OPEN_PAREN: - state->handler = attlist3; - return XML_ROLE_ATTLIST_NONE; - } - return common(state, tok); -} - -static int PTRCALL -attlist3(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_NMTOKEN: - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = attlist4; - return XML_ROLE_ATTRIBUTE_ENUM_VALUE; - } - return common(state, tok); -} - -static int PTRCALL -attlist4(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_CLOSE_PAREN: - state->handler = attlist8; - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_OR: - state->handler = attlist3; - return XML_ROLE_ATTLIST_NONE; - } - return common(state, tok); -} - -static int PTRCALL -attlist5(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_OPEN_PAREN: - state->handler = attlist6; - return XML_ROLE_ATTLIST_NONE; - } - return common(state, tok); -} - -static int PTRCALL -attlist6(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_NAME: - state->handler = attlist7; - return XML_ROLE_ATTRIBUTE_NOTATION_VALUE; - } - return common(state, tok); -} - -static int PTRCALL -attlist7(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_CLOSE_PAREN: - state->handler = attlist8; - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_OR: - state->handler = attlist6; - return XML_ROLE_ATTLIST_NONE; - } - return common(state, tok); -} - -/* default value */ -static int PTRCALL -attlist8(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_POUND_NAME: - if (XmlNameMatchesAscii(enc, - ptr + MIN_BYTES_PER_CHAR(enc), - end, - KW_IMPLIED)) { - state->handler = attlist1; - return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE; - } - if (XmlNameMatchesAscii(enc, - ptr + MIN_BYTES_PER_CHAR(enc), - end, - KW_REQUIRED)) { - state->handler = attlist1; - return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE; - } - if (XmlNameMatchesAscii(enc, - ptr + MIN_BYTES_PER_CHAR(enc), - end, - KW_FIXED)) { - state->handler = attlist9; - return XML_ROLE_ATTLIST_NONE; - } - break; - case XML_TOK_LITERAL: - state->handler = attlist1; - return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE; - } - return common(state, tok); -} - -static int PTRCALL -attlist9(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ATTLIST_NONE; - case XML_TOK_LITERAL: - state->handler = attlist1; - return XML_ROLE_FIXED_ATTRIBUTE_VALUE; - } - return common(state, tok); -} - -static int PTRCALL -element0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ELEMENT_NONE; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = element1; - return XML_ROLE_ELEMENT_NAME; - } - return common(state, tok); -} - -static int PTRCALL -element1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ELEMENT_NONE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) { - state->handler = declClose; - state->role_none = XML_ROLE_ELEMENT_NONE; - return XML_ROLE_CONTENT_EMPTY; - } - if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) { - state->handler = declClose; - state->role_none = XML_ROLE_ELEMENT_NONE; - return XML_ROLE_CONTENT_ANY; - } - break; - case XML_TOK_OPEN_PAREN: - state->handler = element2; - state->level = 1; - return XML_ROLE_GROUP_OPEN; - } - return common(state, tok); -} - -static int PTRCALL -element2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ELEMENT_NONE; - case XML_TOK_POUND_NAME: - if (XmlNameMatchesAscii(enc, - ptr + MIN_BYTES_PER_CHAR(enc), - end, - KW_PCDATA)) { - state->handler = element3; - return XML_ROLE_CONTENT_PCDATA; - } - break; - case XML_TOK_OPEN_PAREN: - state->level = 2; - state->handler = element6; - return XML_ROLE_GROUP_OPEN; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT; - case XML_TOK_NAME_QUESTION: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_OPT; - case XML_TOK_NAME_ASTERISK: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_REP; - case XML_TOK_NAME_PLUS: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_PLUS; - } - return common(state, tok); -} - -static int PTRCALL -element3(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ELEMENT_NONE; - case XML_TOK_CLOSE_PAREN: - state->handler = declClose; - state->role_none = XML_ROLE_ELEMENT_NONE; - return XML_ROLE_GROUP_CLOSE; - case XML_TOK_CLOSE_PAREN_ASTERISK: - state->handler = declClose; - state->role_none = XML_ROLE_ELEMENT_NONE; - return XML_ROLE_GROUP_CLOSE_REP; - case XML_TOK_OR: - state->handler = element4; - return XML_ROLE_ELEMENT_NONE; - } - return common(state, tok); -} - -static int PTRCALL -element4(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ELEMENT_NONE; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = element5; - return XML_ROLE_CONTENT_ELEMENT; - } - return common(state, tok); -} - -static int PTRCALL -element5(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ELEMENT_NONE; - case XML_TOK_CLOSE_PAREN_ASTERISK: - state->handler = declClose; - state->role_none = XML_ROLE_ELEMENT_NONE; - return XML_ROLE_GROUP_CLOSE_REP; - case XML_TOK_OR: - state->handler = element4; - return XML_ROLE_ELEMENT_NONE; - } - return common(state, tok); -} - -static int PTRCALL -element6(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ELEMENT_NONE; - case XML_TOK_OPEN_PAREN: - state->level += 1; - return XML_ROLE_GROUP_OPEN; - case XML_TOK_NAME: - case XML_TOK_PREFIXED_NAME: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT; - case XML_TOK_NAME_QUESTION: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_OPT; - case XML_TOK_NAME_ASTERISK: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_REP; - case XML_TOK_NAME_PLUS: - state->handler = element7; - return XML_ROLE_CONTENT_ELEMENT_PLUS; - } - return common(state, tok); -} - -static int PTRCALL -element7(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_ELEMENT_NONE; - case XML_TOK_CLOSE_PAREN: - state->level -= 1; - if (state->level == 0) { - state->handler = declClose; - state->role_none = XML_ROLE_ELEMENT_NONE; - } - return XML_ROLE_GROUP_CLOSE; - case XML_TOK_CLOSE_PAREN_ASTERISK: - state->level -= 1; - if (state->level == 0) { - state->handler = declClose; - state->role_none = XML_ROLE_ELEMENT_NONE; - } - return XML_ROLE_GROUP_CLOSE_REP; - case XML_TOK_CLOSE_PAREN_QUESTION: - state->level -= 1; - if (state->level == 0) { - state->handler = declClose; - state->role_none = XML_ROLE_ELEMENT_NONE; - } - return XML_ROLE_GROUP_CLOSE_OPT; - case XML_TOK_CLOSE_PAREN_PLUS: - state->level -= 1; - if (state->level == 0) { - state->handler = declClose; - state->role_none = XML_ROLE_ELEMENT_NONE; - } - return XML_ROLE_GROUP_CLOSE_PLUS; - case XML_TOK_COMMA: - state->handler = element6; - return XML_ROLE_GROUP_SEQUENCE; - case XML_TOK_OR: - state->handler = element6; - return XML_ROLE_GROUP_CHOICE; - } - return common(state, tok); -} - -#ifdef XML_DTD - -static int PTRCALL -condSect0(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_NAME: - if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) { - state->handler = condSect1; - return XML_ROLE_NONE; - } - if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) { - state->handler = condSect2; - return XML_ROLE_NONE; - } - break; - } - return common(state, tok); -} - -static int PTRCALL -condSect1(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_OPEN_BRACKET: - state->handler = externalSubset1; - state->includeLevel += 1; - return XML_ROLE_NONE; - } - return common(state, tok); -} - -static int PTRCALL -condSect2(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return XML_ROLE_NONE; - case XML_TOK_OPEN_BRACKET: - state->handler = externalSubset1; - return XML_ROLE_IGNORE_SECT; - } - return common(state, tok); -} - -#endif /* XML_DTD */ - -static int PTRCALL -declClose(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - switch (tok) { - case XML_TOK_PROLOG_S: - return state->role_none; - case XML_TOK_DECL_CLOSE: - setTopLevel(state); - return state->role_none; - } - return common(state, tok); -} - -static int PTRCALL -error(PROLOG_STATE *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc) -{ - return XML_ROLE_NONE; -} - -static int FASTCALL -common(PROLOG_STATE *state, int tok) -{ -#ifdef XML_DTD - if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF) - return XML_ROLE_INNER_PARAM_ENTITY_REF; -#endif - state->handler = error; - return XML_ROLE_ERROR; -} - -void -XmlPrologStateInit(PROLOG_STATE *state) -{ - state->handler = prolog0; -#ifdef XML_DTD - state->documentEntity = 1; - state->includeLevel = 0; - state->inEntityValue = 0; -#endif /* XML_DTD */ -} - -#ifdef XML_DTD - -void -XmlPrologStateInitExternalEntity(PROLOG_STATE *state) -{ - state->handler = externalSubset0; - state->documentEntity = 0; - state->includeLevel = 0; -} - -#endif /* XML_DTD */ diff -Nru simgear-2.10.0/simgear/xml/xmlrole.h simgear-3.0.0/simgear/xml/xmlrole.h --- simgear-2.10.0/simgear/xml/xmlrole.h 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/xmlrole.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,114 +0,0 @@ -/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd - See the file COPYING for copying permission. -*/ - -#ifndef XmlRole_INCLUDED -#define XmlRole_INCLUDED 1 - -#ifdef __VMS -/* 0 1 2 3 0 1 2 3 - 1234567890123456789012345678901 1234567890123456789012345678901 */ -#define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt -#endif - -#include "xmltok.h" - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - XML_ROLE_ERROR = -1, - XML_ROLE_NONE = 0, - XML_ROLE_XML_DECL, - XML_ROLE_INSTANCE_START, - XML_ROLE_DOCTYPE_NONE, - XML_ROLE_DOCTYPE_NAME, - XML_ROLE_DOCTYPE_SYSTEM_ID, - XML_ROLE_DOCTYPE_PUBLIC_ID, - XML_ROLE_DOCTYPE_INTERNAL_SUBSET, - XML_ROLE_DOCTYPE_CLOSE, - XML_ROLE_GENERAL_ENTITY_NAME, - XML_ROLE_PARAM_ENTITY_NAME, - XML_ROLE_ENTITY_NONE, - XML_ROLE_ENTITY_VALUE, - XML_ROLE_ENTITY_SYSTEM_ID, - XML_ROLE_ENTITY_PUBLIC_ID, - XML_ROLE_ENTITY_COMPLETE, - XML_ROLE_ENTITY_NOTATION_NAME, - XML_ROLE_NOTATION_NONE, - XML_ROLE_NOTATION_NAME, - XML_ROLE_NOTATION_SYSTEM_ID, - XML_ROLE_NOTATION_NO_SYSTEM_ID, - XML_ROLE_NOTATION_PUBLIC_ID, - XML_ROLE_ATTRIBUTE_NAME, - XML_ROLE_ATTRIBUTE_TYPE_CDATA, - XML_ROLE_ATTRIBUTE_TYPE_ID, - XML_ROLE_ATTRIBUTE_TYPE_IDREF, - XML_ROLE_ATTRIBUTE_TYPE_IDREFS, - XML_ROLE_ATTRIBUTE_TYPE_ENTITY, - XML_ROLE_ATTRIBUTE_TYPE_ENTITIES, - XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN, - XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS, - XML_ROLE_ATTRIBUTE_ENUM_VALUE, - XML_ROLE_ATTRIBUTE_NOTATION_VALUE, - XML_ROLE_ATTLIST_NONE, - XML_ROLE_ATTLIST_ELEMENT_NAME, - XML_ROLE_IMPLIED_ATTRIBUTE_VALUE, - XML_ROLE_REQUIRED_ATTRIBUTE_VALUE, - XML_ROLE_DEFAULT_ATTRIBUTE_VALUE, - XML_ROLE_FIXED_ATTRIBUTE_VALUE, - XML_ROLE_ELEMENT_NONE, - XML_ROLE_ELEMENT_NAME, - XML_ROLE_CONTENT_ANY, - XML_ROLE_CONTENT_EMPTY, - XML_ROLE_CONTENT_PCDATA, - XML_ROLE_GROUP_OPEN, - XML_ROLE_GROUP_CLOSE, - XML_ROLE_GROUP_CLOSE_REP, - XML_ROLE_GROUP_CLOSE_OPT, - XML_ROLE_GROUP_CLOSE_PLUS, - XML_ROLE_GROUP_CHOICE, - XML_ROLE_GROUP_SEQUENCE, - XML_ROLE_CONTENT_ELEMENT, - XML_ROLE_CONTENT_ELEMENT_REP, - XML_ROLE_CONTENT_ELEMENT_OPT, - XML_ROLE_CONTENT_ELEMENT_PLUS, - XML_ROLE_PI, - XML_ROLE_COMMENT, -#ifdef XML_DTD - XML_ROLE_TEXT_DECL, - XML_ROLE_IGNORE_SECT, - XML_ROLE_INNER_PARAM_ENTITY_REF, -#endif /* XML_DTD */ - XML_ROLE_PARAM_ENTITY_REF -}; - -typedef struct prolog_state { - int (PTRCALL *handler) (struct prolog_state *state, - int tok, - const char *ptr, - const char *end, - const ENCODING *enc); - unsigned level; - int role_none; -#ifdef XML_DTD - unsigned includeLevel; - int documentEntity; - int inEntityValue; -#endif /* XML_DTD */ -} PROLOG_STATE; - -void XmlPrologStateInit(PROLOG_STATE *); -#ifdef XML_DTD -void XmlPrologStateInitExternalEntity(PROLOG_STATE *); -#endif /* XML_DTD */ - -#define XmlTokenRole(state, tok, ptr, end, enc) \ - (((state)->handler)(state, tok, ptr, end, enc)) - -#ifdef __cplusplus -} -#endif - -#endif /* not XmlRole_INCLUDED */ diff -Nru simgear-2.10.0/simgear/xml/xmltok.c simgear-3.0.0/simgear/xml/xmltok.c --- simgear-2.10.0/simgear/xml/xmltok.c 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/xmltok.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1651 +0,0 @@ -/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd - See the file COPYING for copying permission. -*/ - -#include - -#ifdef COMPILED_FROM_DSP -#include "winconfig.h" -#elif defined(MACOS_CLASSIC) -#include "macconfig.h" -#elif defined(__amigaos__) -#include "amigaconfig.h" -#elif defined(__WATCOMC__) -#include "watcomconfig.h" -#else -#ifdef HAVE_EXPAT_CONFIG_H -#include "expat_config.h" -#endif -#endif /* ndef COMPILED_FROM_DSP */ - -#include "expat_external.h" -#include "internal.h" -#include "xmltok.h" -#include "nametab.h" - -#ifdef XML_DTD -#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok) -#else -#define IGNORE_SECTION_TOK_VTABLE /* as nothing */ -#endif - -#define VTABLE1 \ - { PREFIX(prologTok), PREFIX(contentTok), \ - PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \ - { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \ - PREFIX(sameName), \ - PREFIX(nameMatchesAscii), \ - PREFIX(nameLength), \ - PREFIX(skipS), \ - PREFIX(getAtts), \ - PREFIX(charRefNumber), \ - PREFIX(predefinedEntityName), \ - PREFIX(updatePosition), \ - PREFIX(isPublicId) - -#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16) - -#define UCS2_GET_NAMING(pages, hi, lo) \ - (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F))) - -/* A 2 byte UTF-8 representation splits the characters 11 bits between - the bottom 5 and 6 bits of the bytes. We need 8 bits to index into - pages, 3 bits to add to that index and 5 bits to generate the mask. -*/ -#define UTF8_GET_NAMING2(pages, byte) \ - (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ - + ((((byte)[0]) & 3) << 1) \ - + ((((byte)[1]) >> 5) & 1)] \ - & (1 << (((byte)[1]) & 0x1F))) - -/* A 3 byte UTF-8 representation splits the characters 16 bits between - the bottom 4, 6 and 6 bits of the bytes. We need 8 bits to index - into pages, 3 bits to add to that index and 5 bits to generate the - mask. -*/ -#define UTF8_GET_NAMING3(pages, byte) \ - (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ - + ((((byte)[1]) >> 2) & 0xF)] \ - << 3) \ - + ((((byte)[1]) & 3) << 1) \ - + ((((byte)[2]) >> 5) & 1)] \ - & (1 << (((byte)[2]) & 0x1F))) - -#define UTF8_GET_NAMING(pages, p, n) \ - ((n) == 2 \ - ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \ - : ((n) == 3 \ - ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \ - : 0)) - -/* Detection of invalid UTF-8 sequences is based on Table 3.1B - of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/ - with the additional restriction of not allowing the Unicode - code points 0xFFFF and 0xFFFE (sequences EF,BF,BF and EF,BF,BE). - Implementation details: - (A & 0x80) == 0 means A < 0x80 - and - (A & 0xC0) == 0xC0 means A > 0xBF -*/ - -#define UTF8_INVALID2(p) \ - ((*p) < 0xC2 || ((p)[1] & 0x80) == 0 || ((p)[1] & 0xC0) == 0xC0) - -#define UTF8_INVALID3(p) \ - (((p)[2] & 0x80) == 0 \ - || \ - ((*p) == 0xEF && (p)[1] == 0xBF \ - ? \ - (p)[2] > 0xBD \ - : \ - ((p)[2] & 0xC0) == 0xC0) \ - || \ - ((*p) == 0xE0 \ - ? \ - (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \ - : \ - ((p)[1] & 0x80) == 0 \ - || \ - ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0))) - -#define UTF8_INVALID4(p) \ - (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 \ - || \ - ((p)[2] & 0x80) == 0 || ((p)[2] & 0xC0) == 0xC0 \ - || \ - ((*p) == 0xF0 \ - ? \ - (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \ - : \ - ((p)[1] & 0x80) == 0 \ - || \ - ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0))) - -static int PTRFASTCALL -isNever(const ENCODING *enc, const char *p) -{ - return 0; -} - -static int PTRFASTCALL -utf8_isName2(const ENCODING *enc, const char *p) -{ - return UTF8_GET_NAMING2(namePages, (const unsigned char *)p); -} - -static int PTRFASTCALL -utf8_isName3(const ENCODING *enc, const char *p) -{ - return UTF8_GET_NAMING3(namePages, (const unsigned char *)p); -} - -#define utf8_isName4 isNever - -static int PTRFASTCALL -utf8_isNmstrt2(const ENCODING *enc, const char *p) -{ - return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p); -} - -static int PTRFASTCALL -utf8_isNmstrt3(const ENCODING *enc, const char *p) -{ - return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p); -} - -#define utf8_isNmstrt4 isNever - -static int PTRFASTCALL -utf8_isInvalid2(const ENCODING *enc, const char *p) -{ - return UTF8_INVALID2((const unsigned char *)p); -} - -static int PTRFASTCALL -utf8_isInvalid3(const ENCODING *enc, const char *p) -{ - return UTF8_INVALID3((const unsigned char *)p); -} - -static int PTRFASTCALL -utf8_isInvalid4(const ENCODING *enc, const char *p) -{ - return UTF8_INVALID4((const unsigned char *)p); -} - -struct normal_encoding { - ENCODING enc; - unsigned char type[256]; -#ifdef XML_MIN_SIZE - int (PTRFASTCALL *byteType)(const ENCODING *, const char *); - int (PTRFASTCALL *isNameMin)(const ENCODING *, const char *); - int (PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *); - int (PTRFASTCALL *byteToAscii)(const ENCODING *, const char *); - int (PTRCALL *charMatches)(const ENCODING *, const char *, int); -#endif /* XML_MIN_SIZE */ - int (PTRFASTCALL *isName2)(const ENCODING *, const char *); - int (PTRFASTCALL *isName3)(const ENCODING *, const char *); - int (PTRFASTCALL *isName4)(const ENCODING *, const char *); - int (PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *); - int (PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *); - int (PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *); - int (PTRFASTCALL *isInvalid2)(const ENCODING *, const char *); - int (PTRFASTCALL *isInvalid3)(const ENCODING *, const char *); - int (PTRFASTCALL *isInvalid4)(const ENCODING *, const char *); -}; - -#define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *) (enc)) - -#ifdef XML_MIN_SIZE - -#define STANDARD_VTABLE(E) \ - E ## byteType, \ - E ## isNameMin, \ - E ## isNmstrtMin, \ - E ## byteToAscii, \ - E ## charMatches, - -#else - -#define STANDARD_VTABLE(E) /* as nothing */ - -#endif - -#define NORMAL_VTABLE(E) \ - E ## isName2, \ - E ## isName3, \ - E ## isName4, \ - E ## isNmstrt2, \ - E ## isNmstrt3, \ - E ## isNmstrt4, \ - E ## isInvalid2, \ - E ## isInvalid3, \ - E ## isInvalid4 - -static int FASTCALL checkCharRefNumber(int); - -#include "xmltok_impl.h" -#include "ascii.h" - -#ifdef XML_MIN_SIZE -#define sb_isNameMin isNever -#define sb_isNmstrtMin isNever -#endif - -#ifdef XML_MIN_SIZE -#define MINBPC(enc) ((enc)->minBytesPerChar) -#else -/* minimum bytes per character */ -#define MINBPC(enc) 1 -#endif - -#define SB_BYTE_TYPE(enc, p) \ - (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)]) - -#ifdef XML_MIN_SIZE -static int PTRFASTCALL -sb_byteType(const ENCODING *enc, const char *p) -{ - return SB_BYTE_TYPE(enc, p); -} -#define BYTE_TYPE(enc, p) \ - (AS_NORMAL_ENCODING(enc)->byteType(enc, p)) -#else -#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p) -#endif - -#ifdef XML_MIN_SIZE -#define BYTE_TO_ASCII(enc, p) \ - (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p)) -static int PTRFASTCALL -sb_byteToAscii(const ENCODING *enc, const char *p) -{ - return *p; -} -#else -#define BYTE_TO_ASCII(enc, p) (*(p)) -#endif - -#define IS_NAME_CHAR(enc, p, n) \ - (AS_NORMAL_ENCODING(enc)->isName ## n(enc, p)) -#define IS_NMSTRT_CHAR(enc, p, n) \ - (AS_NORMAL_ENCODING(enc)->isNmstrt ## n(enc, p)) -#define IS_INVALID_CHAR(enc, p, n) \ - (AS_NORMAL_ENCODING(enc)->isInvalid ## n(enc, p)) - -#ifdef XML_MIN_SIZE -#define IS_NAME_CHAR_MINBPC(enc, p) \ - (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p)) -#define IS_NMSTRT_CHAR_MINBPC(enc, p) \ - (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p)) -#else -#define IS_NAME_CHAR_MINBPC(enc, p) (0) -#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0) -#endif - -#ifdef XML_MIN_SIZE -#define CHAR_MATCHES(enc, p, c) \ - (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c)) -static int PTRCALL -sb_charMatches(const ENCODING *enc, const char *p, int c) -{ - return *p == c; -} -#else -/* c is an ASCII character */ -#define CHAR_MATCHES(enc, p, c) (*(p) == c) -#endif - -#define PREFIX(ident) normal_ ## ident -#define XML_TOK_IMPL_C -#include "xmltok_impl.c" -#undef XML_TOK_IMPL_C - -#undef MINBPC -#undef BYTE_TYPE -#undef BYTE_TO_ASCII -#undef CHAR_MATCHES -#undef IS_NAME_CHAR -#undef IS_NAME_CHAR_MINBPC -#undef IS_NMSTRT_CHAR -#undef IS_NMSTRT_CHAR_MINBPC -#undef IS_INVALID_CHAR - -enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */ - UTF8_cval1 = 0x00, - UTF8_cval2 = 0xc0, - UTF8_cval3 = 0xe0, - UTF8_cval4 = 0xf0 -}; - -static void PTRCALL -utf8_toUtf8(const ENCODING *enc, - const char **fromP, const char *fromLim, - char **toP, const char *toLim) -{ - char *to; - const char *from; - if (fromLim - *fromP > toLim - *toP) { - /* Avoid copying partial characters. */ - for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--) - if (((unsigned char)fromLim[-1] & 0xc0) != 0x80) - break; - } - for (to = *toP, from = *fromP; from != fromLim; from++, to++) - *to = *from; - *fromP = from; - *toP = to; -} - -static void PTRCALL -utf8_toUtf16(const ENCODING *enc, - const char **fromP, const char *fromLim, - unsigned short **toP, const unsigned short *toLim) -{ - unsigned short *to = *toP; - const char *from = *fromP; - while (from != fromLim && to != toLim) { - switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) { - case BT_LEAD2: - *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f)); - from += 2; - break; - case BT_LEAD3: - *to++ = (unsigned short)(((from[0] & 0xf) << 12) - | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f)); - from += 3; - break; - case BT_LEAD4: - { - unsigned long n; - if (to + 1 == toLim) - goto after; - n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) - | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f); - n -= 0x10000; - to[0] = (unsigned short)((n >> 10) | 0xD800); - to[1] = (unsigned short)((n & 0x3FF) | 0xDC00); - to += 2; - from += 4; - } - break; - default: - *to++ = *from++; - break; - } - } -after: - *fromP = from; - *toP = to; -} - -#ifdef XML_NS -static const struct normal_encoding utf8_encoding_ns = { - { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, - { -#include "asciitab.h" -#include "utf8tab.h" - }, - STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) -}; -#endif - -static const struct normal_encoding utf8_encoding = { - { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, - { -#define BT_COLON BT_NMSTRT -#include "asciitab.h" -#undef BT_COLON -#include "utf8tab.h" - }, - STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) -}; - -#ifdef XML_NS - -static const struct normal_encoding internal_utf8_encoding_ns = { - { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, - { -#include "iasciitab.h" -#include "utf8tab.h" - }, - STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) -}; - -#endif - -static const struct normal_encoding internal_utf8_encoding = { - { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, - { -#define BT_COLON BT_NMSTRT -#include "iasciitab.h" -#undef BT_COLON -#include "utf8tab.h" - }, - STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) -}; - -static void PTRCALL -latin1_toUtf8(const ENCODING *enc, - const char **fromP, const char *fromLim, - char **toP, const char *toLim) -{ - for (;;) { - unsigned char c; - if (*fromP == fromLim) - break; - c = (unsigned char)**fromP; - if (c & 0x80) { - if (toLim - *toP < 2) - break; - *(*toP)++ = (char)((c >> 6) | UTF8_cval2); - *(*toP)++ = (char)((c & 0x3f) | 0x80); - (*fromP)++; - } - else { - if (*toP == toLim) - break; - *(*toP)++ = *(*fromP)++; - } - } -} - -static void PTRCALL -latin1_toUtf16(const ENCODING *enc, - const char **fromP, const char *fromLim, - unsigned short **toP, const unsigned short *toLim) -{ - while (*fromP != fromLim && *toP != toLim) - *(*toP)++ = (unsigned char)*(*fromP)++; -} - -#ifdef XML_NS - -static const struct normal_encoding latin1_encoding_ns = { - { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, - { -#include "asciitab.h" -#include "latin1tab.h" - }, - STANDARD_VTABLE(sb_) -}; - -#endif - -static const struct normal_encoding latin1_encoding = { - { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, - { -#define BT_COLON BT_NMSTRT -#include "asciitab.h" -#undef BT_COLON -#include "latin1tab.h" - }, - STANDARD_VTABLE(sb_) -}; - -static void PTRCALL -ascii_toUtf8(const ENCODING *enc, - const char **fromP, const char *fromLim, - char **toP, const char *toLim) -{ - while (*fromP != fromLim && *toP != toLim) - *(*toP)++ = *(*fromP)++; -} - -#ifdef XML_NS - -static const struct normal_encoding ascii_encoding_ns = { - { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, - { -#include "asciitab.h" -/* BT_NONXML == 0 */ - }, - STANDARD_VTABLE(sb_) -}; - -#endif - -static const struct normal_encoding ascii_encoding = { - { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, - { -#define BT_COLON BT_NMSTRT -#include "asciitab.h" -#undef BT_COLON -/* BT_NONXML == 0 */ - }, - STANDARD_VTABLE(sb_) -}; - -static int PTRFASTCALL -unicode_byte_type(char hi, char lo) -{ - switch ((unsigned char)hi) { - case 0xD8: case 0xD9: case 0xDA: case 0xDB: - return BT_LEAD4; - case 0xDC: case 0xDD: case 0xDE: case 0xDF: - return BT_TRAIL; - case 0xFF: - switch ((unsigned char)lo) { - case 0xFF: - case 0xFE: - return BT_NONXML; - } - break; - } - return BT_NONASCII; -} - -#define DEFINE_UTF16_TO_UTF8(E) \ -static void PTRCALL \ -E ## toUtf8(const ENCODING *enc, \ - const char **fromP, const char *fromLim, \ - char **toP, const char *toLim) \ -{ \ - const char *from; \ - for (from = *fromP; from != fromLim; from += 2) { \ - int plane; \ - unsigned char lo2; \ - unsigned char lo = GET_LO(from); \ - unsigned char hi = GET_HI(from); \ - switch (hi) { \ - case 0: \ - if (lo < 0x80) { \ - if (*toP == toLim) { \ - *fromP = from; \ - return; \ - } \ - *(*toP)++ = lo; \ - break; \ - } \ - /* fall through */ \ - case 0x1: case 0x2: case 0x3: \ - case 0x4: case 0x5: case 0x6: case 0x7: \ - if (toLim - *toP < 2) { \ - *fromP = from; \ - return; \ - } \ - *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \ - *(*toP)++ = ((lo & 0x3f) | 0x80); \ - break; \ - default: \ - if (toLim - *toP < 3) { \ - *fromP = from; \ - return; \ - } \ - /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \ - *(*toP)++ = ((hi >> 4) | UTF8_cval3); \ - *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \ - *(*toP)++ = ((lo & 0x3f) | 0x80); \ - break; \ - case 0xD8: case 0xD9: case 0xDA: case 0xDB: \ - if (toLim - *toP < 4) { \ - *fromP = from; \ - return; \ - } \ - plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \ - *(*toP)++ = ((plane >> 2) | UTF8_cval4); \ - *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \ - from += 2; \ - lo2 = GET_LO(from); \ - *(*toP)++ = (((lo & 0x3) << 4) \ - | ((GET_HI(from) & 0x3) << 2) \ - | (lo2 >> 6) \ - | 0x80); \ - *(*toP)++ = ((lo2 & 0x3f) | 0x80); \ - break; \ - } \ - } \ - *fromP = from; \ -} - -#define DEFINE_UTF16_TO_UTF16(E) \ -static void PTRCALL \ -E ## toUtf16(const ENCODING *enc, \ - const char **fromP, const char *fromLim, \ - unsigned short **toP, const unsigned short *toLim) \ -{ \ - /* Avoid copying first half only of surrogate */ \ - if (fromLim - *fromP > ((toLim - *toP) << 1) \ - && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \ - fromLim -= 2; \ - for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \ - *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \ -} - -#define SET2(ptr, ch) \ - (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8))) -#define GET_LO(ptr) ((unsigned char)(ptr)[0]) -#define GET_HI(ptr) ((unsigned char)(ptr)[1]) - -DEFINE_UTF16_TO_UTF8(little2_) -DEFINE_UTF16_TO_UTF16(little2_) - -#undef SET2 -#undef GET_LO -#undef GET_HI - -#define SET2(ptr, ch) \ - (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF))) -#define GET_LO(ptr) ((unsigned char)(ptr)[1]) -#define GET_HI(ptr) ((unsigned char)(ptr)[0]) - -DEFINE_UTF16_TO_UTF8(big2_) -DEFINE_UTF16_TO_UTF16(big2_) - -#undef SET2 -#undef GET_LO -#undef GET_HI - -#define LITTLE2_BYTE_TYPE(enc, p) \ - ((p)[1] == 0 \ - ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ - : unicode_byte_type((p)[1], (p)[0])) -#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1) -#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c) -#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \ - UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) -#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ - UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0]) - -#ifdef XML_MIN_SIZE - -static int PTRFASTCALL -little2_byteType(const ENCODING *enc, const char *p) -{ - return LITTLE2_BYTE_TYPE(enc, p); -} - -static int PTRFASTCALL -little2_byteToAscii(const ENCODING *enc, const char *p) -{ - return LITTLE2_BYTE_TO_ASCII(enc, p); -} - -static int PTRCALL -little2_charMatches(const ENCODING *enc, const char *p, int c) -{ - return LITTLE2_CHAR_MATCHES(enc, p, c); -} - -static int PTRFASTCALL -little2_isNameMin(const ENCODING *enc, const char *p) -{ - return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p); -} - -static int PTRFASTCALL -little2_isNmstrtMin(const ENCODING *enc, const char *p) -{ - return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p); -} - -#undef VTABLE -#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16 - -#else /* not XML_MIN_SIZE */ - -#undef PREFIX -#define PREFIX(ident) little2_ ## ident -#define MINBPC(enc) 2 -/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ -#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p) -#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p) -#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c) -#define IS_NAME_CHAR(enc, p, n) 0 -#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) -#define IS_NMSTRT_CHAR(enc, p, n) (0) -#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) - -#define XML_TOK_IMPL_C -#include "xmltok_impl.c" -#undef XML_TOK_IMPL_C - -#undef MINBPC -#undef BYTE_TYPE -#undef BYTE_TO_ASCII -#undef CHAR_MATCHES -#undef IS_NAME_CHAR -#undef IS_NAME_CHAR_MINBPC -#undef IS_NMSTRT_CHAR -#undef IS_NMSTRT_CHAR_MINBPC -#undef IS_INVALID_CHAR - -#endif /* not XML_MIN_SIZE */ - -#ifdef XML_NS - -static const struct normal_encoding little2_encoding_ns = { - { VTABLE, 2, 0, -#if BYTEORDER == 1234 - 1 -#else - 0 -#endif - }, - { -#include "asciitab.h" -#include "latin1tab.h" - }, - STANDARD_VTABLE(little2_) -}; - -#endif - -static const struct normal_encoding little2_encoding = { - { VTABLE, 2, 0, -#if BYTEORDER == 1234 - 1 -#else - 0 -#endif - }, - { -#define BT_COLON BT_NMSTRT -#include "asciitab.h" -#undef BT_COLON -#include "latin1tab.h" - }, - STANDARD_VTABLE(little2_) -}; - -#if BYTEORDER != 4321 - -#ifdef XML_NS - -static const struct normal_encoding internal_little2_encoding_ns = { - { VTABLE, 2, 0, 1 }, - { -#include "iasciitab.h" -#include "latin1tab.h" - }, - STANDARD_VTABLE(little2_) -}; - -#endif - -static const struct normal_encoding internal_little2_encoding = { - { VTABLE, 2, 0, 1 }, - { -#define BT_COLON BT_NMSTRT -#include "iasciitab.h" -#undef BT_COLON -#include "latin1tab.h" - }, - STANDARD_VTABLE(little2_) -}; - -#endif - - -#define BIG2_BYTE_TYPE(enc, p) \ - ((p)[0] == 0 \ - ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ - : unicode_byte_type((p)[0], (p)[1])) -#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1) -#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c) -#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \ - UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) -#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ - UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1]) - -#ifdef XML_MIN_SIZE - -static int PTRFASTCALL -big2_byteType(const ENCODING *enc, const char *p) -{ - return BIG2_BYTE_TYPE(enc, p); -} - -static int PTRFASTCALL -big2_byteToAscii(const ENCODING *enc, const char *p) -{ - return BIG2_BYTE_TO_ASCII(enc, p); -} - -static int PTRCALL -big2_charMatches(const ENCODING *enc, const char *p, int c) -{ - return BIG2_CHAR_MATCHES(enc, p, c); -} - -static int PTRFASTCALL -big2_isNameMin(const ENCODING *enc, const char *p) -{ - return BIG2_IS_NAME_CHAR_MINBPC(enc, p); -} - -static int PTRFASTCALL -big2_isNmstrtMin(const ENCODING *enc, const char *p) -{ - return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p); -} - -#undef VTABLE -#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16 - -#else /* not XML_MIN_SIZE */ - -#undef PREFIX -#define PREFIX(ident) big2_ ## ident -#define MINBPC(enc) 2 -/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ -#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p) -#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p) -#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c) -#define IS_NAME_CHAR(enc, p, n) 0 -#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p) -#define IS_NMSTRT_CHAR(enc, p, n) (0) -#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) - -#define XML_TOK_IMPL_C -#include "xmltok_impl.c" -#undef XML_TOK_IMPL_C - -#undef MINBPC -#undef BYTE_TYPE -#undef BYTE_TO_ASCII -#undef CHAR_MATCHES -#undef IS_NAME_CHAR -#undef IS_NAME_CHAR_MINBPC -#undef IS_NMSTRT_CHAR -#undef IS_NMSTRT_CHAR_MINBPC -#undef IS_INVALID_CHAR - -#endif /* not XML_MIN_SIZE */ - -#ifdef XML_NS - -static const struct normal_encoding big2_encoding_ns = { - { VTABLE, 2, 0, -#if BYTEORDER == 4321 - 1 -#else - 0 -#endif - }, - { -#include "asciitab.h" -#include "latin1tab.h" - }, - STANDARD_VTABLE(big2_) -}; - -#endif - -static const struct normal_encoding big2_encoding = { - { VTABLE, 2, 0, -#if BYTEORDER == 4321 - 1 -#else - 0 -#endif - }, - { -#define BT_COLON BT_NMSTRT -#include "asciitab.h" -#undef BT_COLON -#include "latin1tab.h" - }, - STANDARD_VTABLE(big2_) -}; - -#if BYTEORDER != 1234 - -#ifdef XML_NS - -static const struct normal_encoding internal_big2_encoding_ns = { - { VTABLE, 2, 0, 1 }, - { -#include "iasciitab.h" -#include "latin1tab.h" - }, - STANDARD_VTABLE(big2_) -}; - -#endif - -static const struct normal_encoding internal_big2_encoding = { - { VTABLE, 2, 0, 1 }, - { -#define BT_COLON BT_NMSTRT -#include "iasciitab.h" -#undef BT_COLON -#include "latin1tab.h" - }, - STANDARD_VTABLE(big2_) -}; - -#endif - -#undef PREFIX - -static int FASTCALL -streqci(const char *s1, const char *s2) -{ - for (;;) { - char c1 = *s1++; - char c2 = *s2++; - if (ASCII_a <= c1 && c1 <= ASCII_z) - c1 += ASCII_A - ASCII_a; - if (ASCII_a <= c2 && c2 <= ASCII_z) - c2 += ASCII_A - ASCII_a; - if (c1 != c2) - return 0; - if (!c1) - break; - } - return 1; -} - -static void PTRCALL -initUpdatePosition(const ENCODING *enc, const char *ptr, - const char *end, POSITION *pos) -{ - normal_updatePosition(&utf8_encoding.enc, ptr, end, pos); -} - -static int -toAscii(const ENCODING *enc, const char *ptr, const char *end) -{ - char buf[1]; - char *p = buf; - XmlUtf8Convert(enc, &ptr, end, &p, p + 1); - if (p == buf) - return -1; - else - return buf[0]; -} - -static int FASTCALL -isSpace(int c) -{ - switch (c) { - case 0x20: - case 0xD: - case 0xA: - case 0x9: - return 1; - } - return 0; -} - -/* Return 1 if there's just optional white space or there's an S - followed by name=val. -*/ -static int -parsePseudoAttribute(const ENCODING *enc, - const char *ptr, - const char *end, - const char **namePtr, - const char **nameEndPtr, - const char **valPtr, - const char **nextTokPtr) -{ - int c; - char open; - if (ptr == end) { - *namePtr = NULL; - return 1; - } - if (!isSpace(toAscii(enc, ptr, end))) { - *nextTokPtr = ptr; - return 0; - } - do { - ptr += enc->minBytesPerChar; - } while (isSpace(toAscii(enc, ptr, end))); - if (ptr == end) { - *namePtr = NULL; - return 1; - } - *namePtr = ptr; - for (;;) { - c = toAscii(enc, ptr, end); - if (c == -1) { - *nextTokPtr = ptr; - return 0; - } - if (c == ASCII_EQUALS) { - *nameEndPtr = ptr; - break; - } - if (isSpace(c)) { - *nameEndPtr = ptr; - do { - ptr += enc->minBytesPerChar; - } while (isSpace(c = toAscii(enc, ptr, end))); - if (c != ASCII_EQUALS) { - *nextTokPtr = ptr; - return 0; - } - break; - } - ptr += enc->minBytesPerChar; - } - if (ptr == *namePtr) { - *nextTokPtr = ptr; - return 0; - } - ptr += enc->minBytesPerChar; - c = toAscii(enc, ptr, end); - while (isSpace(c)) { - ptr += enc->minBytesPerChar; - c = toAscii(enc, ptr, end); - } - if (c != ASCII_QUOT && c != ASCII_APOS) { - *nextTokPtr = ptr; - return 0; - } - open = (char)c; - ptr += enc->minBytesPerChar; - *valPtr = ptr; - for (;; ptr += enc->minBytesPerChar) { - c = toAscii(enc, ptr, end); - if (c == open) - break; - if (!(ASCII_a <= c && c <= ASCII_z) - && !(ASCII_A <= c && c <= ASCII_Z) - && !(ASCII_0 <= c && c <= ASCII_9) - && c != ASCII_PERIOD - && c != ASCII_MINUS - && c != ASCII_UNDERSCORE) { - *nextTokPtr = ptr; - return 0; - } - } - *nextTokPtr = ptr + enc->minBytesPerChar; - return 1; -} - -static const char KW_version[] = { - ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0' -}; - -static const char KW_encoding[] = { - ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0' -}; - -static const char KW_standalone[] = { - ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o, - ASCII_n, ASCII_e, '\0' -}; - -static const char KW_yes[] = { - ASCII_y, ASCII_e, ASCII_s, '\0' -}; - -static const char KW_no[] = { - ASCII_n, ASCII_o, '\0' -}; - -static int -doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, - const char *, - const char *), - int isGeneralTextEntity, - const ENCODING *enc, - const char *ptr, - const char *end, - const char **badPtr, - const char **versionPtr, - const char **versionEndPtr, - const char **encodingName, - const ENCODING **encoding, - int *standalone) -{ - const char *val = NULL; - const char *name = NULL; - const char *nameEnd = NULL; - ptr += 5 * enc->minBytesPerChar; - end -= 2 * enc->minBytesPerChar; - if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr) - || !name) { - *badPtr = ptr; - return 0; - } - if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) { - if (!isGeneralTextEntity) { - *badPtr = name; - return 0; - } - } - else { - if (versionPtr) - *versionPtr = val; - if (versionEndPtr) - *versionEndPtr = ptr; - if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { - *badPtr = ptr; - return 0; - } - if (!name) { - if (isGeneralTextEntity) { - /* a TextDecl must have an EncodingDecl */ - *badPtr = ptr; - return 0; - } - return 1; - } - } - if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) { - int c = toAscii(enc, val, end); - if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) { - *badPtr = val; - return 0; - } - if (encodingName) - *encodingName = val; - if (encoding) - *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar); - if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { - *badPtr = ptr; - return 0; - } - if (!name) - return 1; - } - if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone) - || isGeneralTextEntity) { - *badPtr = name; - return 0; - } - if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) { - if (standalone) - *standalone = 1; - } - else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) { - if (standalone) - *standalone = 0; - } - else { - *badPtr = val; - return 0; - } - while (isSpace(toAscii(enc, ptr, end))) - ptr += enc->minBytesPerChar; - if (ptr != end) { - *badPtr = ptr; - return 0; - } - return 1; -} - -static int FASTCALL -checkCharRefNumber(int result) -{ - switch (result >> 8) { - case 0xD8: case 0xD9: case 0xDA: case 0xDB: - case 0xDC: case 0xDD: case 0xDE: case 0xDF: - return -1; - case 0: - if (latin1_encoding.type[result] == BT_NONXML) - return -1; - break; - case 0xFF: - if (result == 0xFFFE || result == 0xFFFF) - return -1; - break; - } - return result; -} - -int FASTCALL -XmlUtf8Encode(int c, char *buf) -{ - enum { - /* minN is minimum legal resulting value for N byte sequence */ - min2 = 0x80, - min3 = 0x800, - min4 = 0x10000 - }; - - if (c < 0) - return 0; - if (c < min2) { - buf[0] = (char)(c | UTF8_cval1); - return 1; - } - if (c < min3) { - buf[0] = (char)((c >> 6) | UTF8_cval2); - buf[1] = (char)((c & 0x3f) | 0x80); - return 2; - } - if (c < min4) { - buf[0] = (char)((c >> 12) | UTF8_cval3); - buf[1] = (char)(((c >> 6) & 0x3f) | 0x80); - buf[2] = (char)((c & 0x3f) | 0x80); - return 3; - } - if (c < 0x110000) { - buf[0] = (char)((c >> 18) | UTF8_cval4); - buf[1] = (char)(((c >> 12) & 0x3f) | 0x80); - buf[2] = (char)(((c >> 6) & 0x3f) | 0x80); - buf[3] = (char)((c & 0x3f) | 0x80); - return 4; - } - return 0; -} - -int FASTCALL -XmlUtf16Encode(int charNum, unsigned short *buf) -{ - if (charNum < 0) - return 0; - if (charNum < 0x10000) { - buf[0] = (unsigned short)charNum; - return 1; - } - if (charNum < 0x110000) { - charNum -= 0x10000; - buf[0] = (unsigned short)((charNum >> 10) + 0xD800); - buf[1] = (unsigned short)((charNum & 0x3FF) + 0xDC00); - return 2; - } - return 0; -} - -struct unknown_encoding { - struct normal_encoding normal; - CONVERTER convert; - void *userData; - unsigned short utf16[256]; - char utf8[256][4]; -}; - -#define AS_UNKNOWN_ENCODING(enc) ((const struct unknown_encoding *) (enc)) - -int -XmlSizeOfUnknownEncoding(void) -{ - return sizeof(struct unknown_encoding); -} - -static int PTRFASTCALL -unknown_isName(const ENCODING *enc, const char *p) -{ - const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); - int c = uenc->convert(uenc->userData, p); - if (c & ~0xFFFF) - return 0; - return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF); -} - -static int PTRFASTCALL -unknown_isNmstrt(const ENCODING *enc, const char *p) -{ - const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); - int c = uenc->convert(uenc->userData, p); - if (c & ~0xFFFF) - return 0; - return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF); -} - -static int PTRFASTCALL -unknown_isInvalid(const ENCODING *enc, const char *p) -{ - const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); - int c = uenc->convert(uenc->userData, p); - return (c & ~0xFFFF) || checkCharRefNumber(c) < 0; -} - -static void PTRCALL -unknown_toUtf8(const ENCODING *enc, - const char **fromP, const char *fromLim, - char **toP, const char *toLim) -{ - const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); - char buf[XML_UTF8_ENCODE_MAX]; - for (;;) { - const char *utf8; - int n; - if (*fromP == fromLim) - break; - utf8 = uenc->utf8[(unsigned char)**fromP]; - n = *utf8++; - if (n == 0) { - int c = uenc->convert(uenc->userData, *fromP); - n = XmlUtf8Encode(c, buf); - if (n > toLim - *toP) - break; - utf8 = buf; - *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP] - - (BT_LEAD2 - 2)); - } - else { - if (n > toLim - *toP) - break; - (*fromP)++; - } - do { - *(*toP)++ = *utf8++; - } while (--n != 0); - } -} - -static void PTRCALL -unknown_toUtf16(const ENCODING *enc, - const char **fromP, const char *fromLim, - unsigned short **toP, const unsigned short *toLim) -{ - const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); - while (*fromP != fromLim && *toP != toLim) { - unsigned short c = uenc->utf16[(unsigned char)**fromP]; - if (c == 0) { - c = (unsigned short) - uenc->convert(uenc->userData, *fromP); - *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP] - - (BT_LEAD2 - 2)); - } - else - (*fromP)++; - *(*toP)++ = c; - } -} - -ENCODING * -XmlInitUnknownEncoding(void *mem, - int *table, - CONVERTER convert, - void *userData) -{ - int i; - struct unknown_encoding *e = (struct unknown_encoding *)mem; - for (i = 0; i < (int)sizeof(struct normal_encoding); i++) - ((char *)mem)[i] = ((char *)&latin1_encoding)[i]; - for (i = 0; i < 128; i++) - if (latin1_encoding.type[i] != BT_OTHER - && latin1_encoding.type[i] != BT_NONXML - && table[i] != i) - return 0; - for (i = 0; i < 256; i++) { - int c = table[i]; - if (c == -1) { - e->normal.type[i] = BT_MALFORM; - /* This shouldn't really get used. */ - e->utf16[i] = 0xFFFF; - e->utf8[i][0] = 1; - e->utf8[i][1] = 0; - } - else if (c < 0) { - if (c < -4) - return 0; - e->normal.type[i] = (unsigned char)(BT_LEAD2 - (c + 2)); - e->utf8[i][0] = 0; - e->utf16[i] = 0; - } - else if (c < 0x80) { - if (latin1_encoding.type[c] != BT_OTHER - && latin1_encoding.type[c] != BT_NONXML - && c != i) - return 0; - e->normal.type[i] = latin1_encoding.type[c]; - e->utf8[i][0] = 1; - e->utf8[i][1] = (char)c; - e->utf16[i] = (unsigned short)(c == 0 ? 0xFFFF : c); - } - else if (checkCharRefNumber(c) < 0) { - e->normal.type[i] = BT_NONXML; - /* This shouldn't really get used. */ - e->utf16[i] = 0xFFFF; - e->utf8[i][0] = 1; - e->utf8[i][1] = 0; - } - else { - if (c > 0xFFFF) - return 0; - if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff)) - e->normal.type[i] = BT_NMSTRT; - else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff)) - e->normal.type[i] = BT_NAME; - else - e->normal.type[i] = BT_OTHER; - e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1); - e->utf16[i] = (unsigned short)c; - } - } - e->userData = userData; - e->convert = convert; - if (convert) { - e->normal.isName2 = unknown_isName; - e->normal.isName3 = unknown_isName; - e->normal.isName4 = unknown_isName; - e->normal.isNmstrt2 = unknown_isNmstrt; - e->normal.isNmstrt3 = unknown_isNmstrt; - e->normal.isNmstrt4 = unknown_isNmstrt; - e->normal.isInvalid2 = unknown_isInvalid; - e->normal.isInvalid3 = unknown_isInvalid; - e->normal.isInvalid4 = unknown_isInvalid; - } - e->normal.enc.utf8Convert = unknown_toUtf8; - e->normal.enc.utf16Convert = unknown_toUtf16; - return &(e->normal.enc); -} - -/* If this enumeration is changed, getEncodingIndex and encodings -must also be changed. */ -enum { - UNKNOWN_ENC = -1, - ISO_8859_1_ENC = 0, - US_ASCII_ENC, - UTF_8_ENC, - UTF_16_ENC, - UTF_16BE_ENC, - UTF_16LE_ENC, - /* must match encodingNames up to here */ - NO_ENC -}; - -static const char KW_ISO_8859_1[] = { - ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9, - ASCII_MINUS, ASCII_1, '\0' -}; -static const char KW_US_ASCII[] = { - ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I, - '\0' -}; -static const char KW_UTF_8[] = { - ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0' -}; -static const char KW_UTF_16[] = { - ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0' -}; -static const char KW_UTF_16BE[] = { - ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E, - '\0' -}; -static const char KW_UTF_16LE[] = { - ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E, - '\0' -}; - -static int FASTCALL -getEncodingIndex(const char *name) -{ - static const char * const encodingNames[] = { - KW_ISO_8859_1, - KW_US_ASCII, - KW_UTF_8, - KW_UTF_16, - KW_UTF_16BE, - KW_UTF_16LE, - }; - int i; - if (name == NULL) - return NO_ENC; - for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++) - if (streqci(name, encodingNames[i])) - return i; - return UNKNOWN_ENC; -} - -/* For binary compatibility, we store the index of the encoding - specified at initialization in the isUtf16 member. -*/ - -#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16) -#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i) - -/* This is what detects the encoding. encodingTable maps from - encoding indices to encodings; INIT_ENC_INDEX(enc) is the index of - the external (protocol) specified encoding; state is - XML_CONTENT_STATE if we're parsing an external text entity, and - XML_PROLOG_STATE otherwise. -*/ - - -static int -initScan(const ENCODING * const *encodingTable, - const INIT_ENCODING *enc, - int state, - const char *ptr, - const char *end, - const char **nextTokPtr) -{ - const ENCODING **encPtr; - - if (ptr == end) - return XML_TOK_NONE; - encPtr = enc->encPtr; - if (ptr + 1 == end) { - /* only a single byte available for auto-detection */ -#ifndef XML_DTD /* FIXME */ - /* a well-formed document entity must have more than one byte */ - if (state != XML_CONTENT_STATE) - return XML_TOK_PARTIAL; -#endif - /* so we're parsing an external text entity... */ - /* if UTF-16 was externally specified, then we need at least 2 bytes */ - switch (INIT_ENC_INDEX(enc)) { - case UTF_16_ENC: - case UTF_16LE_ENC: - case UTF_16BE_ENC: - return XML_TOK_PARTIAL; - } - switch ((unsigned char)*ptr) { - case 0xFE: - case 0xFF: - case 0xEF: /* possibly first byte of UTF-8 BOM */ - if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC - && state == XML_CONTENT_STATE) - break; - /* fall through */ - case 0x00: - case 0x3C: - return XML_TOK_PARTIAL; - } - } - else { - switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) { - case 0xFEFF: - if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC - && state == XML_CONTENT_STATE) - break; - *nextTokPtr = ptr + 2; - *encPtr = encodingTable[UTF_16BE_ENC]; - return XML_TOK_BOM; - /* 00 3C is handled in the default case */ - case 0x3C00: - if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC - || INIT_ENC_INDEX(enc) == UTF_16_ENC) - && state == XML_CONTENT_STATE) - break; - *encPtr = encodingTable[UTF_16LE_ENC]; - return XmlTok(*encPtr, state, ptr, end, nextTokPtr); - case 0xFFFE: - if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC - && state == XML_CONTENT_STATE) - break; - *nextTokPtr = ptr + 2; - *encPtr = encodingTable[UTF_16LE_ENC]; - return XML_TOK_BOM; - case 0xEFBB: - /* Maybe a UTF-8 BOM (EF BB BF) */ - /* If there's an explicitly specified (external) encoding - of ISO-8859-1 or some flavour of UTF-16 - and this is an external text entity, - don't look for the BOM, - because it might be a legal data. - */ - if (state == XML_CONTENT_STATE) { - int e = INIT_ENC_INDEX(enc); - if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC - || e == UTF_16LE_ENC || e == UTF_16_ENC) - break; - } - if (ptr + 2 == end) - return XML_TOK_PARTIAL; - if ((unsigned char)ptr[2] == 0xBF) { - *nextTokPtr = ptr + 3; - *encPtr = encodingTable[UTF_8_ENC]; - return XML_TOK_BOM; - } - break; - default: - if (ptr[0] == '\0') { - /* 0 isn't a legal data character. Furthermore a document - entity can only start with ASCII characters. So the only - way this can fail to be big-endian UTF-16 if it it's an - external parsed general entity that's labelled as - UTF-16LE. - */ - if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC) - break; - *encPtr = encodingTable[UTF_16BE_ENC]; - return XmlTok(*encPtr, state, ptr, end, nextTokPtr); - } - else if (ptr[1] == '\0') { - /* We could recover here in the case: - - parsing an external entity - - second byte is 0 - - no externally specified encoding - - no encoding declaration - by assuming UTF-16LE. But we don't, because this would mean when - presented just with a single byte, we couldn't reliably determine - whether we needed further bytes. - */ - if (state == XML_CONTENT_STATE) - break; - *encPtr = encodingTable[UTF_16LE_ENC]; - return XmlTok(*encPtr, state, ptr, end, nextTokPtr); - } - break; - } - } - *encPtr = encodingTable[INIT_ENC_INDEX(enc)]; - return XmlTok(*encPtr, state, ptr, end, nextTokPtr); -} - - -#define NS(x) x -#define ns(x) x -#define XML_TOK_NS_C -#include "xmltok_ns.c" -#undef XML_TOK_NS_C -#undef NS -#undef ns - -#ifdef XML_NS - -#define NS(x) x ## NS -#define ns(x) x ## _ns - -#define XML_TOK_NS_C -#include "xmltok_ns.c" -#undef XML_TOK_NS_C - -#undef NS -#undef ns - -ENCODING * -XmlInitUnknownEncodingNS(void *mem, - int *table, - CONVERTER convert, - void *userData) -{ - ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData); - if (enc) - ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON; - return enc; -} - -#endif /* XML_NS */ diff -Nru simgear-2.10.0/simgear/xml/xmltok.h simgear-3.0.0/simgear/xml/xmltok.h --- simgear-2.10.0/simgear/xml/xmltok.h 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/xmltok.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,316 +0,0 @@ -/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd - See the file COPYING for copying permission. -*/ - -#ifndef XmlTok_INCLUDED -#define XmlTok_INCLUDED 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* The following token may be returned by XmlContentTok */ -#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be - start of illegal ]]> sequence */ -/* The following tokens may be returned by both XmlPrologTok and - XmlContentTok. -*/ -#define XML_TOK_NONE -4 /* The string to be scanned is empty */ -#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan; - might be part of CRLF sequence */ -#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ -#define XML_TOK_PARTIAL -1 /* only part of a token */ -#define XML_TOK_INVALID 0 - -/* The following tokens are returned by XmlContentTok; some are also - returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok. -*/ -#define XML_TOK_START_TAG_WITH_ATTS 1 -#define XML_TOK_START_TAG_NO_ATTS 2 -#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag */ -#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 -#define XML_TOK_END_TAG 5 -#define XML_TOK_DATA_CHARS 6 -#define XML_TOK_DATA_NEWLINE 7 -#define XML_TOK_CDATA_SECT_OPEN 8 -#define XML_TOK_ENTITY_REF 9 -#define XML_TOK_CHAR_REF 10 /* numeric character reference */ - -/* The following tokens may be returned by both XmlPrologTok and - XmlContentTok. -*/ -#define XML_TOK_PI 11 /* processing instruction */ -#define XML_TOK_XML_DECL 12 /* XML decl or text decl */ -#define XML_TOK_COMMENT 13 -#define XML_TOK_BOM 14 /* Byte order mark */ - -/* The following tokens are returned only by XmlPrologTok */ -#define XML_TOK_PROLOG_S 15 -#define XML_TOK_DECL_OPEN 16 /* */ -#define XML_TOK_NAME 18 -#define XML_TOK_NMTOKEN 19 -#define XML_TOK_POUND_NAME 20 /* #name */ -#define XML_TOK_OR 21 /* | */ -#define XML_TOK_PERCENT 22 -#define XML_TOK_OPEN_PAREN 23 -#define XML_TOK_CLOSE_PAREN 24 -#define XML_TOK_OPEN_BRACKET 25 -#define XML_TOK_CLOSE_BRACKET 26 -#define XML_TOK_LITERAL 27 -#define XML_TOK_PARAM_ENTITY_REF 28 -#define XML_TOK_INSTANCE_START 29 - -/* The following occur only in element type declarations */ -#define XML_TOK_NAME_QUESTION 30 /* name? */ -#define XML_TOK_NAME_ASTERISK 31 /* name* */ -#define XML_TOK_NAME_PLUS 32 /* name+ */ -#define XML_TOK_COND_SECT_OPEN 33 /* */ -#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ -#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ -#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ -#define XML_TOK_COMMA 38 - -/* The following token is returned only by XmlAttributeValueTok */ -#define XML_TOK_ATTRIBUTE_VALUE_S 39 - -/* The following token is returned only by XmlCdataSectionTok */ -#define XML_TOK_CDATA_SECT_CLOSE 40 - -/* With namespace processing this is returned by XmlPrologTok for a - name with a colon. -*/ -#define XML_TOK_PREFIXED_NAME 41 - -#ifdef XML_DTD -#define XML_TOK_IGNORE_SECT 42 -#endif /* XML_DTD */ - -#ifdef XML_DTD -#define XML_N_STATES 4 -#else /* not XML_DTD */ -#define XML_N_STATES 3 -#endif /* not XML_DTD */ - -#define XML_PROLOG_STATE 0 -#define XML_CONTENT_STATE 1 -#define XML_CDATA_SECTION_STATE 2 -#ifdef XML_DTD -#define XML_IGNORE_SECTION_STATE 3 -#endif /* XML_DTD */ - -#define XML_N_LITERAL_TYPES 2 -#define XML_ATTRIBUTE_VALUE_LITERAL 0 -#define XML_ENTITY_VALUE_LITERAL 1 - -/* The size of the buffer passed to XmlUtf8Encode must be at least this. */ -#define XML_UTF8_ENCODE_MAX 4 -/* The size of the buffer passed to XmlUtf16Encode must be at least this. */ -#define XML_UTF16_ENCODE_MAX 2 - -typedef struct position { - /* first line and first column are 0 not 1 */ - XML_Size lineNumber; - XML_Size columnNumber; -} POSITION; - -typedef struct { - const char *name; - const char *valuePtr; - const char *valueEnd; - char normalized; -} ATTRIBUTE; - -struct encoding; -typedef struct encoding ENCODING; - -typedef int (PTRCALL *SCANNER)(const ENCODING *, - const char *, - const char *, - const char **); - -struct encoding { - SCANNER scanners[XML_N_STATES]; - SCANNER literalScanners[XML_N_LITERAL_TYPES]; - int (PTRCALL *sameName)(const ENCODING *, - const char *, - const char *); - int (PTRCALL *nameMatchesAscii)(const ENCODING *, - const char *, - const char *, - const char *); - int (PTRFASTCALL *nameLength)(const ENCODING *, const char *); - const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *); - int (PTRCALL *getAtts)(const ENCODING *enc, - const char *ptr, - int attsMax, - ATTRIBUTE *atts); - int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr); - int (PTRCALL *predefinedEntityName)(const ENCODING *, - const char *, - const char *); - void (PTRCALL *updatePosition)(const ENCODING *, - const char *ptr, - const char *end, - POSITION *); - int (PTRCALL *isPublicId)(const ENCODING *enc, - const char *ptr, - const char *end, - const char **badPtr); - void (PTRCALL *utf8Convert)(const ENCODING *enc, - const char **fromP, - const char *fromLim, - char **toP, - const char *toLim); - void (PTRCALL *utf16Convert)(const ENCODING *enc, - const char **fromP, - const char *fromLim, - unsigned short **toP, - const unsigned short *toLim); - int minBytesPerChar; - char isUtf8; - char isUtf16; -}; - -/* Scan the string starting at ptr until the end of the next complete - token, but do not scan past eptr. Return an integer giving the - type of token. - - Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set. - - Return XML_TOK_PARTIAL when the string does not contain a complete - token; nextTokPtr will not be set. - - Return XML_TOK_INVALID when the string does not start a valid - token; nextTokPtr will be set to point to the character which made - the token invalid. - - Otherwise the string starts with a valid token; nextTokPtr will be - set to point to the character following the end of that token. - - Each data character counts as a single token, but adjacent data - characters may be returned together. Similarly for characters in - the prolog outside literals, comments and processing instructions. -*/ - - -#define XmlTok(enc, state, ptr, end, nextTokPtr) \ - (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) - -#define XmlPrologTok(enc, ptr, end, nextTokPtr) \ - XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) - -#define XmlContentTok(enc, ptr, end, nextTokPtr) \ - XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) - -#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ - XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) - -#ifdef XML_DTD - -#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \ - XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr) - -#endif /* XML_DTD */ - -/* This is used for performing a 2nd-level tokenization on the content - of a literal that has already been returned by XmlTok. -*/ -#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ - (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) - -#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ - XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) - -#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ - XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) - -#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2)) - -#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \ - (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2)) - -#define XmlNameLength(enc, ptr) \ - (((enc)->nameLength)(enc, ptr)) - -#define XmlSkipS(enc, ptr) \ - (((enc)->skipS)(enc, ptr)) - -#define XmlGetAttributes(enc, ptr, attsMax, atts) \ - (((enc)->getAtts)(enc, ptr, attsMax, atts)) - -#define XmlCharRefNumber(enc, ptr) \ - (((enc)->charRefNumber)(enc, ptr)) - -#define XmlPredefinedEntityName(enc, ptr, end) \ - (((enc)->predefinedEntityName)(enc, ptr, end)) - -#define XmlUpdatePosition(enc, ptr, end, pos) \ - (((enc)->updatePosition)(enc, ptr, end, pos)) - -#define XmlIsPublicId(enc, ptr, end, badPtr) \ - (((enc)->isPublicId)(enc, ptr, end, badPtr)) - -#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ - (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) - -#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ - (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) - -typedef struct { - ENCODING initEnc; - const ENCODING **encPtr; -} INIT_ENCODING; - -int XmlParseXmlDecl(int isGeneralTextEntity, - const ENCODING *enc, - const char *ptr, - const char *end, - const char **badPtr, - const char **versionPtr, - const char **versionEndPtr, - const char **encodingNamePtr, - const ENCODING **namedEncodingPtr, - int *standalonePtr); - -int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name); -const ENCODING *XmlGetUtf8InternalEncoding(void); -const ENCODING *XmlGetUtf16InternalEncoding(void); -int FASTCALL XmlUtf8Encode(int charNumber, char *buf); -int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf); -int XmlSizeOfUnknownEncoding(void); - - -typedef int (XMLCALL *CONVERTER) (void *userData, const char *p); - -ENCODING * -XmlInitUnknownEncoding(void *mem, - int *table, - CONVERTER convert, - void *userData); - -int XmlParseXmlDeclNS(int isGeneralTextEntity, - const ENCODING *enc, - const char *ptr, - const char *end, - const char **badPtr, - const char **versionPtr, - const char **versionEndPtr, - const char **encodingNamePtr, - const ENCODING **namedEncodingPtr, - int *standalonePtr); - -int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name); -const ENCODING *XmlGetUtf8InternalEncodingNS(void); -const ENCODING *XmlGetUtf16InternalEncodingNS(void); -ENCODING * -XmlInitUnknownEncodingNS(void *mem, - int *table, - CONVERTER convert, - void *userData); -#ifdef __cplusplus -} -#endif - -#endif /* not XmlTok_INCLUDED */ diff -Nru simgear-2.10.0/simgear/xml/xmltok_impl.c simgear-3.0.0/simgear/xml/xmltok_impl.c --- simgear-2.10.0/simgear/xml/xmltok_impl.c 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/xmltok_impl.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,1783 +0,0 @@ -/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd - See the file COPYING for copying permission. -*/ - -/* This file is included! */ -#ifdef XML_TOK_IMPL_C - -#ifndef IS_INVALID_CHAR -#define IS_INVALID_CHAR(enc, ptr, n) (0) -#endif - -#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \ - case BT_LEAD ## n: \ - if (end - ptr < n) \ - return XML_TOK_PARTIAL_CHAR; \ - if (IS_INVALID_CHAR(enc, ptr, n)) { \ - *(nextTokPtr) = (ptr); \ - return XML_TOK_INVALID; \ - } \ - ptr += n; \ - break; - -#define INVALID_CASES(ptr, nextTokPtr) \ - INVALID_LEAD_CASE(2, ptr, nextTokPtr) \ - INVALID_LEAD_CASE(3, ptr, nextTokPtr) \ - INVALID_LEAD_CASE(4, ptr, nextTokPtr) \ - case BT_NONXML: \ - case BT_MALFORM: \ - case BT_TRAIL: \ - *(nextTokPtr) = (ptr); \ - return XML_TOK_INVALID; - -#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \ - case BT_LEAD ## n: \ - if (end - ptr < n) \ - return XML_TOK_PARTIAL_CHAR; \ - if (!IS_NAME_CHAR(enc, ptr, n)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; \ - } \ - ptr += n; \ - break; - -#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \ - case BT_NONASCII: \ - if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; \ - } \ - case BT_NMSTRT: \ - case BT_HEX: \ - case BT_DIGIT: \ - case BT_NAME: \ - case BT_MINUS: \ - ptr += MINBPC(enc); \ - break; \ - CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \ - CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \ - CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr) - -#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ - case BT_LEAD ## n: \ - if (end - ptr < n) \ - return XML_TOK_PARTIAL_CHAR; \ - if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; \ - } \ - ptr += n; \ - break; - -#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \ - case BT_NONASCII: \ - if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; \ - } \ - case BT_NMSTRT: \ - case BT_HEX: \ - ptr += MINBPC(enc); \ - break; \ - CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \ - CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \ - CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr) - -#ifndef PREFIX -#define PREFIX(ident) ident -#endif - -/* ptr points to character following " */ - switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) { - case BT_S: case BT_CR: case BT_LF: case BT_PERCNT: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - /* fall through */ - case BT_S: case BT_CR: case BT_LF: - *nextTokPtr = ptr; - return XML_TOK_DECL_OPEN; - case BT_NMSTRT: - case BT_HEX: - ptr += MINBPC(enc); - break; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -} - -static int PTRCALL -PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr, - const char *end, int *tokPtr) -{ - int upper = 0; - *tokPtr = XML_TOK_PI; - if (end - ptr != MINBPC(enc)*3) - return 1; - switch (BYTE_TO_ASCII(enc, ptr)) { - case ASCII_x: - break; - case ASCII_X: - upper = 1; - break; - default: - return 1; - } - ptr += MINBPC(enc); - switch (BYTE_TO_ASCII(enc, ptr)) { - case ASCII_m: - break; - case ASCII_M: - upper = 1; - break; - default: - return 1; - } - ptr += MINBPC(enc); - switch (BYTE_TO_ASCII(enc, ptr)) { - case ASCII_l: - break; - case ASCII_L: - upper = 1; - break; - default: - return 1; - } - if (upper) - return 0; - *tokPtr = XML_TOK_XML_DECL; - return 1; -} - -/* ptr points to character following " 1) { - size_t n = end - ptr; - if (n & (MINBPC(enc) - 1)) { - n &= ~(MINBPC(enc) - 1); - if (n == 0) - return XML_TOK_PARTIAL; - end = ptr + n; - } - } - switch (BYTE_TYPE(enc, ptr)) { - case BT_RSQB: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) - break; - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { - ptr -= MINBPC(enc); - break; - } - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_CDATA_SECT_CLOSE; - case BT_CR: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - if (BYTE_TYPE(enc, ptr) == BT_LF) - ptr += MINBPC(enc); - *nextTokPtr = ptr; - return XML_TOK_DATA_NEWLINE; - case BT_LF: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_DATA_NEWLINE; - INVALID_CASES(ptr, nextTokPtr) - default: - ptr += MINBPC(enc); - break; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: \ - if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_DATA_CHARS; \ - } \ - ptr += n; \ - break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_NONXML: - case BT_MALFORM: - case BT_TRAIL: - case BT_CR: - case BT_LF: - case BT_RSQB: - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - default: - ptr += MINBPC(enc); - break; - } - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; -} - -/* ptr points to character following " 1) { - size_t n = end - ptr; - if (n & (MINBPC(enc) - 1)) { - n &= ~(MINBPC(enc) - 1); - if (n == 0) - return XML_TOK_PARTIAL; - end = ptr + n; - } - } - switch (BYTE_TYPE(enc, ptr)) { - case BT_LT: - return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_AMP: - return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_CR: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_TRAILING_CR; - if (BYTE_TYPE(enc, ptr) == BT_LF) - ptr += MINBPC(enc); - *nextTokPtr = ptr; - return XML_TOK_DATA_NEWLINE; - case BT_LF: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_DATA_NEWLINE; - case BT_RSQB: - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_TRAILING_RSQB; - if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) - break; - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_TRAILING_RSQB; - if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { - ptr -= MINBPC(enc); - break; - } - *nextTokPtr = ptr; - return XML_TOK_INVALID; - INVALID_CASES(ptr, nextTokPtr) - default: - ptr += MINBPC(enc); - break; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: \ - if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ - *nextTokPtr = ptr; \ - return XML_TOK_DATA_CHARS; \ - } \ - ptr += n; \ - break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_RSQB: - if (ptr + MINBPC(enc) != end) { - if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) { - ptr += MINBPC(enc); - break; - } - if (ptr + 2*MINBPC(enc) != end) { - if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) { - ptr += MINBPC(enc); - break; - } - *nextTokPtr = ptr + 2*MINBPC(enc); - return XML_TOK_INVALID; - } - } - /* fall through */ - case BT_AMP: - case BT_LT: - case BT_NONXML: - case BT_MALFORM: - case BT_TRAIL: - case BT_CR: - case BT_LF: - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - default: - ptr += MINBPC(enc); - break; - } - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; -} - -/* ptr points to character following "%" */ - -static int PTRCALL -PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) - case BT_S: case BT_LF: case BT_CR: case BT_PERCNT: - *nextTokPtr = ptr; - return XML_TOK_PERCENT; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) - case BT_SEMI: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_PARAM_ENTITY_REF; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return XML_TOK_PARTIAL; -} - -static int PTRCALL -PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) - case BT_CR: case BT_LF: case BT_S: - case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR: - *nextTokPtr = ptr; - return XML_TOK_POUND_NAME; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return -XML_TOK_POUND_NAME; -} - -static int PTRCALL -PREFIX(scanLit)(int open, const ENCODING *enc, - const char *ptr, const char *end, - const char **nextTokPtr) -{ - while (ptr != end) { - int t = BYTE_TYPE(enc, ptr); - switch (t) { - INVALID_CASES(ptr, nextTokPtr) - case BT_QUOT: - case BT_APOS: - ptr += MINBPC(enc); - if (t != open) - break; - if (ptr == end) - return -XML_TOK_LITERAL; - *nextTokPtr = ptr; - switch (BYTE_TYPE(enc, ptr)) { - case BT_S: case BT_CR: case BT_LF: - case BT_GT: case BT_PERCNT: case BT_LSQB: - return XML_TOK_LITERAL; - default: - return XML_TOK_INVALID; - } - default: - ptr += MINBPC(enc); - break; - } - } - return XML_TOK_PARTIAL; -} - -static int PTRCALL -PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - int tok; - if (ptr == end) - return XML_TOK_NONE; - if (MINBPC(enc) > 1) { - size_t n = end - ptr; - if (n & (MINBPC(enc) - 1)) { - n &= ~(MINBPC(enc) - 1); - if (n == 0) - return XML_TOK_PARTIAL; - end = ptr + n; - } - } - switch (BYTE_TYPE(enc, ptr)) { - case BT_QUOT: - return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_APOS: - return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_LT: - { - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_PARTIAL; - switch (BYTE_TYPE(enc, ptr)) { - case BT_EXCL: - return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_QUEST: - return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_NMSTRT: - case BT_HEX: - case BT_NONASCII: - case BT_LEAD2: - case BT_LEAD3: - case BT_LEAD4: - *nextTokPtr = ptr - MINBPC(enc); - return XML_TOK_INSTANCE_START; - } - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - case BT_CR: - if (ptr + MINBPC(enc) == end) { - *nextTokPtr = end; - /* indicate that this might be part of a CR/LF pair */ - return -XML_TOK_PROLOG_S; - } - /* fall through */ - case BT_S: case BT_LF: - for (;;) { - ptr += MINBPC(enc); - if (ptr == end) - break; - switch (BYTE_TYPE(enc, ptr)) { - case BT_S: case BT_LF: - break; - case BT_CR: - /* don't split CR/LF pair */ - if (ptr + MINBPC(enc) != end) - break; - /* fall through */ - default: - *nextTokPtr = ptr; - return XML_TOK_PROLOG_S; - } - } - *nextTokPtr = ptr; - return XML_TOK_PROLOG_S; - case BT_PERCNT: - return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); - case BT_COMMA: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_COMMA; - case BT_LSQB: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_OPEN_BRACKET; - case BT_RSQB: - ptr += MINBPC(enc); - if (ptr == end) - return -XML_TOK_CLOSE_BRACKET; - if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { - if (ptr + MINBPC(enc) == end) - return XML_TOK_PARTIAL; - if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) { - *nextTokPtr = ptr + 2*MINBPC(enc); - return XML_TOK_COND_SECT_CLOSE; - } - } - *nextTokPtr = ptr; - return XML_TOK_CLOSE_BRACKET; - case BT_LPAR: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_OPEN_PAREN; - case BT_RPAR: - ptr += MINBPC(enc); - if (ptr == end) - return -XML_TOK_CLOSE_PAREN; - switch (BYTE_TYPE(enc, ptr)) { - case BT_AST: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_CLOSE_PAREN_ASTERISK; - case BT_QUEST: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_CLOSE_PAREN_QUESTION; - case BT_PLUS: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_CLOSE_PAREN_PLUS; - case BT_CR: case BT_LF: case BT_S: - case BT_GT: case BT_COMMA: case BT_VERBAR: - case BT_RPAR: - *nextTokPtr = ptr; - return XML_TOK_CLOSE_PAREN; - } - *nextTokPtr = ptr; - return XML_TOK_INVALID; - case BT_VERBAR: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_OR; - case BT_GT: - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_DECL_CLOSE; - case BT_NUM: - return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr); -#define LEAD_CASE(n) \ - case BT_LEAD ## n: \ - if (end - ptr < n) \ - return XML_TOK_PARTIAL_CHAR; \ - if (IS_NMSTRT_CHAR(enc, ptr, n)) { \ - ptr += n; \ - tok = XML_TOK_NAME; \ - break; \ - } \ - if (IS_NAME_CHAR(enc, ptr, n)) { \ - ptr += n; \ - tok = XML_TOK_NMTOKEN; \ - break; \ - } \ - *nextTokPtr = ptr; \ - return XML_TOK_INVALID; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_NMSTRT: - case BT_HEX: - tok = XML_TOK_NAME; - ptr += MINBPC(enc); - break; - case BT_DIGIT: - case BT_NAME: - case BT_MINUS: -#ifdef XML_NS - case BT_COLON: -#endif - tok = XML_TOK_NMTOKEN; - ptr += MINBPC(enc); - break; - case BT_NONASCII: - if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { - ptr += MINBPC(enc); - tok = XML_TOK_NAME; - break; - } - if (IS_NAME_CHAR_MINBPC(enc, ptr)) { - ptr += MINBPC(enc); - tok = XML_TOK_NMTOKEN; - break; - } - /* fall through */ - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) - case BT_GT: case BT_RPAR: case BT_COMMA: - case BT_VERBAR: case BT_LSQB: case BT_PERCNT: - case BT_S: case BT_CR: case BT_LF: - *nextTokPtr = ptr; - return tok; -#ifdef XML_NS - case BT_COLON: - ptr += MINBPC(enc); - switch (tok) { - case XML_TOK_NAME: - if (ptr == end) - return XML_TOK_PARTIAL; - tok = XML_TOK_PREFIXED_NAME; - switch (BYTE_TYPE(enc, ptr)) { - CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) - default: - tok = XML_TOK_NMTOKEN; - break; - } - break; - case XML_TOK_PREFIXED_NAME: - tok = XML_TOK_NMTOKEN; - break; - } - break; -#endif - case BT_PLUS: - if (tok == XML_TOK_NMTOKEN) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_NAME_PLUS; - case BT_AST: - if (tok == XML_TOK_NMTOKEN) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_NAME_ASTERISK; - case BT_QUEST: - if (tok == XML_TOK_NMTOKEN) { - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_NAME_QUESTION; - default: - *nextTokPtr = ptr; - return XML_TOK_INVALID; - } - } - return -tok; -} - -static int PTRCALL -PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, - const char *end, const char **nextTokPtr) -{ - const char *start; - if (ptr == end) - return XML_TOK_NONE; - start = ptr; - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: ptr += n; break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_AMP: - if (ptr == start) - return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_LT: - /* this is for inside entity references */ - *nextTokPtr = ptr; - return XML_TOK_INVALID; - case BT_LF: - if (ptr == start) { - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_DATA_NEWLINE; - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_CR: - if (ptr == start) { - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_TRAILING_CR; - if (BYTE_TYPE(enc, ptr) == BT_LF) - ptr += MINBPC(enc); - *nextTokPtr = ptr; - return XML_TOK_DATA_NEWLINE; - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_S: - if (ptr == start) { - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_ATTRIBUTE_VALUE_S; - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - default: - ptr += MINBPC(enc); - break; - } - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; -} - -static int PTRCALL -PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, - const char *end, const char **nextTokPtr) -{ - const char *start; - if (ptr == end) - return XML_TOK_NONE; - start = ptr; - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: ptr += n; break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_AMP: - if (ptr == start) - return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_PERCNT: - if (ptr == start) { - int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc), - end, nextTokPtr); - return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok; - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_LF: - if (ptr == start) { - *nextTokPtr = ptr + MINBPC(enc); - return XML_TOK_DATA_NEWLINE; - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - case BT_CR: - if (ptr == start) { - ptr += MINBPC(enc); - if (ptr == end) - return XML_TOK_TRAILING_CR; - if (BYTE_TYPE(enc, ptr) == BT_LF) - ptr += MINBPC(enc); - *nextTokPtr = ptr; - return XML_TOK_DATA_NEWLINE; - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; - default: - ptr += MINBPC(enc); - break; - } - } - *nextTokPtr = ptr; - return XML_TOK_DATA_CHARS; -} - -#ifdef XML_DTD - -static int PTRCALL -PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, - const char *end, const char **nextTokPtr) -{ - int level = 0; - if (MINBPC(enc) > 1) { - size_t n = end - ptr; - if (n & (MINBPC(enc) - 1)) { - n &= ~(MINBPC(enc) - 1); - end = ptr + n; - } - } - while (ptr != end) { - switch (BYTE_TYPE(enc, ptr)) { - INVALID_CASES(ptr, nextTokPtr) - case BT_LT: - if ((ptr += MINBPC(enc)) == end) - return XML_TOK_PARTIAL; - if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) { - if ((ptr += MINBPC(enc)) == end) - return XML_TOK_PARTIAL; - if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) { - ++level; - ptr += MINBPC(enc); - } - } - break; - case BT_RSQB: - if ((ptr += MINBPC(enc)) == end) - return XML_TOK_PARTIAL; - if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { - if ((ptr += MINBPC(enc)) == end) - return XML_TOK_PARTIAL; - if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { - ptr += MINBPC(enc); - if (level == 0) { - *nextTokPtr = ptr; - return XML_TOK_IGNORE_SECT; - } - --level; - } - } - break; - default: - ptr += MINBPC(enc); - break; - } - } - return XML_TOK_PARTIAL; -} - -#endif /* XML_DTD */ - -static int PTRCALL -PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, - const char **badPtr) -{ - ptr += MINBPC(enc); - end -= MINBPC(enc); - for (; ptr != end; ptr += MINBPC(enc)) { - switch (BYTE_TYPE(enc, ptr)) { - case BT_DIGIT: - case BT_HEX: - case BT_MINUS: - case BT_APOS: - case BT_LPAR: - case BT_RPAR: - case BT_PLUS: - case BT_COMMA: - case BT_SOL: - case BT_EQUALS: - case BT_QUEST: - case BT_CR: - case BT_LF: - case BT_SEMI: - case BT_EXCL: - case BT_AST: - case BT_PERCNT: - case BT_NUM: -#ifdef XML_NS - case BT_COLON: -#endif - break; - case BT_S: - if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) { - *badPtr = ptr; - return 0; - } - break; - case BT_NAME: - case BT_NMSTRT: - if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f)) - break; - default: - switch (BYTE_TO_ASCII(enc, ptr)) { - case 0x24: /* $ */ - case 0x40: /* @ */ - break; - default: - *badPtr = ptr; - return 0; - } - break; - } - } - return 1; -} - -/* This must only be called for a well-formed start-tag or empty - element tag. Returns the number of attributes. Pointers to the - first attsMax attributes are stored in atts. -*/ - -static int PTRCALL -PREFIX(getAtts)(const ENCODING *enc, const char *ptr, - int attsMax, ATTRIBUTE *atts) -{ - enum { other, inName, inValue } state = inName; - int nAtts = 0; - int open = 0; /* defined when state == inValue; - initialization just to shut up compilers */ - - for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) { - switch (BYTE_TYPE(enc, ptr)) { -#define START_NAME \ - if (state == other) { \ - if (nAtts < attsMax) { \ - atts[nAtts].name = ptr; \ - atts[nAtts].normalized = 1; \ - } \ - state = inName; \ - } -#define LEAD_CASE(n) \ - case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_NONASCII: - case BT_NMSTRT: - case BT_HEX: - START_NAME - break; -#undef START_NAME - case BT_QUOT: - if (state != inValue) { - if (nAtts < attsMax) - atts[nAtts].valuePtr = ptr + MINBPC(enc); - state = inValue; - open = BT_QUOT; - } - else if (open == BT_QUOT) { - state = other; - if (nAtts < attsMax) - atts[nAtts].valueEnd = ptr; - nAtts++; - } - break; - case BT_APOS: - if (state != inValue) { - if (nAtts < attsMax) - atts[nAtts].valuePtr = ptr + MINBPC(enc); - state = inValue; - open = BT_APOS; - } - else if (open == BT_APOS) { - state = other; - if (nAtts < attsMax) - atts[nAtts].valueEnd = ptr; - nAtts++; - } - break; - case BT_AMP: - if (nAtts < attsMax) - atts[nAtts].normalized = 0; - break; - case BT_S: - if (state == inName) - state = other; - else if (state == inValue - && nAtts < attsMax - && atts[nAtts].normalized - && (ptr == atts[nAtts].valuePtr - || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE - || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE - || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open)) - atts[nAtts].normalized = 0; - break; - case BT_CR: case BT_LF: - /* This case ensures that the first attribute name is counted - Apart from that we could just change state on the quote. */ - if (state == inName) - state = other; - else if (state == inValue && nAtts < attsMax) - atts[nAtts].normalized = 0; - break; - case BT_GT: - case BT_SOL: - if (state != inValue) - return nAtts; - break; - default: - break; - } - } - /* not reached */ -} - -static int PTRFASTCALL -PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr) -{ - int result = 0; - /* skip &# */ - ptr += 2*MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, ASCII_x)) { - for (ptr += MINBPC(enc); - !CHAR_MATCHES(enc, ptr, ASCII_SEMI); - ptr += MINBPC(enc)) { - int c = BYTE_TO_ASCII(enc, ptr); - switch (c) { - case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4: - case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9: - result <<= 4; - result |= (c - ASCII_0); - break; - case ASCII_A: case ASCII_B: case ASCII_C: - case ASCII_D: case ASCII_E: case ASCII_F: - result <<= 4; - result += 10 + (c - ASCII_A); - break; - case ASCII_a: case ASCII_b: case ASCII_c: - case ASCII_d: case ASCII_e: case ASCII_f: - result <<= 4; - result += 10 + (c - ASCII_a); - break; - } - if (result >= 0x110000) - return -1; - } - } - else { - for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) { - int c = BYTE_TO_ASCII(enc, ptr); - result *= 10; - result += (c - ASCII_0); - if (result >= 0x110000) - return -1; - } - } - return checkCharRefNumber(result); -} - -static int PTRCALL -PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr, - const char *end) -{ - switch ((end - ptr)/MINBPC(enc)) { - case 2: - if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) { - switch (BYTE_TO_ASCII(enc, ptr)) { - case ASCII_l: - return ASCII_LT; - case ASCII_g: - return ASCII_GT; - } - } - break; - case 3: - if (CHAR_MATCHES(enc, ptr, ASCII_a)) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, ASCII_m)) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, ASCII_p)) - return ASCII_AMP; - } - } - break; - case 4: - switch (BYTE_TO_ASCII(enc, ptr)) { - case ASCII_q: - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, ASCII_u)) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, ASCII_o)) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, ASCII_t)) - return ASCII_QUOT; - } - } - break; - case ASCII_a: - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, ASCII_p)) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, ASCII_o)) { - ptr += MINBPC(enc); - if (CHAR_MATCHES(enc, ptr, ASCII_s)) - return ASCII_APOS; - } - } - break; - } - } - return 0; -} - -static int PTRCALL -PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2) -{ - for (;;) { - switch (BYTE_TYPE(enc, ptr1)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: \ - if (*ptr1++ != *ptr2++) \ - return 0; - LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2) -#undef LEAD_CASE - /* fall through */ - if (*ptr1++ != *ptr2++) - return 0; - break; - case BT_NONASCII: - case BT_NMSTRT: -#ifdef XML_NS - case BT_COLON: -#endif - case BT_HEX: - case BT_DIGIT: - case BT_NAME: - case BT_MINUS: - if (*ptr2++ != *ptr1++) - return 0; - if (MINBPC(enc) > 1) { - if (*ptr2++ != *ptr1++) - return 0; - if (MINBPC(enc) > 2) { - if (*ptr2++ != *ptr1++) - return 0; - if (MINBPC(enc) > 3) { - if (*ptr2++ != *ptr1++) - return 0; - } - } - } - break; - default: - if (MINBPC(enc) == 1 && *ptr1 == *ptr2) - return 1; - switch (BYTE_TYPE(enc, ptr2)) { - case BT_LEAD2: - case BT_LEAD3: - case BT_LEAD4: - case BT_NONASCII: - case BT_NMSTRT: -#ifdef XML_NS - case BT_COLON: -#endif - case BT_HEX: - case BT_DIGIT: - case BT_NAME: - case BT_MINUS: - return 0; - default: - return 1; - } - } - } - /* not reached */ -} - -static int PTRCALL -PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1, - const char *end1, const char *ptr2) -{ - for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) { - if (ptr1 == end1) - return 0; - if (!CHAR_MATCHES(enc, ptr1, *ptr2)) - return 0; - } - return ptr1 == end1; -} - -static int PTRFASTCALL -PREFIX(nameLength)(const ENCODING *enc, const char *ptr) -{ - const char *start = ptr; - for (;;) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: ptr += n; break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_NONASCII: - case BT_NMSTRT: -#ifdef XML_NS - case BT_COLON: -#endif - case BT_HEX: - case BT_DIGIT: - case BT_NAME: - case BT_MINUS: - ptr += MINBPC(enc); - break; - default: - return (int)(ptr - start); - } - } -} - -static const char * PTRFASTCALL -PREFIX(skipS)(const ENCODING *enc, const char *ptr) -{ - for (;;) { - switch (BYTE_TYPE(enc, ptr)) { - case BT_LF: - case BT_CR: - case BT_S: - ptr += MINBPC(enc); - break; - default: - return ptr; - } - } -} - -static void PTRCALL -PREFIX(updatePosition)(const ENCODING *enc, - const char *ptr, - const char *end, - POSITION *pos) -{ - while (ptr < end) { - switch (BYTE_TYPE(enc, ptr)) { -#define LEAD_CASE(n) \ - case BT_LEAD ## n: \ - ptr += n; \ - break; - LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) -#undef LEAD_CASE - case BT_LF: - pos->columnNumber = (XML_Size)-1; - pos->lineNumber++; - ptr += MINBPC(enc); - break; - case BT_CR: - pos->lineNumber++; - ptr += MINBPC(enc); - if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF) - ptr += MINBPC(enc); - pos->columnNumber = (XML_Size)-1; - break; - default: - ptr += MINBPC(enc); - break; - } - pos->columnNumber++; - } -} - -#undef DO_LEAD_CASE -#undef MULTIBYTE_CASES -#undef INVALID_CASES -#undef CHECK_NAME_CASE -#undef CHECK_NAME_CASES -#undef CHECK_NMSTRT_CASE -#undef CHECK_NMSTRT_CASES - -#endif /* XML_TOK_IMPL_C */ diff -Nru simgear-2.10.0/simgear/xml/xmltok_impl.h simgear-3.0.0/simgear/xml/xmltok_impl.h --- simgear-2.10.0/simgear/xml/xmltok_impl.h 2010-12-18 03:37:16.000000000 +0000 +++ simgear-3.0.0/simgear/xml/xmltok_impl.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,71 +0,0 @@ -/* -The contents of this file are subject to the Mozilla Public License -Version 1.1 (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.mozilla.org/MPL/ - -Software distributed under the License is distributed on an "AS IS" -basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -License for the specific language governing rights and limitations -under the License. - -The Original Code is expat. - -The Initial Developer of the Original Code is James Clark. -Portions created by James Clark are Copyright (C) 1998, 1999 -James Clark. All Rights Reserved. - -Contributor(s): - -Alternatively, the contents of this file may be used under the terms -of the GNU General Public License (the "GPL"), in which case the -provisions of the GPL are applicable instead of those above. If you -wish to allow use of your version of this file only under the terms of -the GPL and not to allow others to use your version of this file under -the MPL, indicate your decision by deleting the provisions above and -replace them with the notice and other provisions required by the -GPL. If you do not delete the provisions above, a recipient may use -your version of this file under either the MPL or the GPL. -*/ - -enum { - BT_NONXML, - BT_MALFORM, - BT_LT, - BT_AMP, - BT_RSQB, - BT_LEAD2, - BT_LEAD3, - BT_LEAD4, - BT_TRAIL, - BT_CR, - BT_LF, - BT_GT, - BT_QUOT, - BT_APOS, - BT_EQUALS, - BT_QUEST, - BT_EXCL, - BT_SOL, - BT_SEMI, - BT_NUM, - BT_LSQB, - BT_S, - BT_NMSTRT, - BT_COLON, - BT_HEX, - BT_DIGIT, - BT_NAME, - BT_MINUS, - BT_OTHER, /* known not to be a name or name start character */ - BT_NONASCII, /* might be a name or name start character */ - BT_PERCNT, - BT_LPAR, - BT_RPAR, - BT_AST, - BT_PLUS, - BT_COMMA, - BT_VERBAR -}; - -#include diff -Nru simgear-2.10.0/simgear/xml/xmltok_ns.c simgear-3.0.0/simgear/xml/xmltok_ns.c --- simgear-2.10.0/simgear/xml/xmltok_ns.c 2012-06-26 20:05:58.000000000 +0000 +++ simgear-3.0.0/simgear/xml/xmltok_ns.c 1970-01-01 00:00:00.000000000 +0000 @@ -1,115 +0,0 @@ -/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd - See the file COPYING for copying permission. -*/ - -/* This file is included! */ -#ifdef XML_TOK_NS_C - -const ENCODING * -NS(XmlGetUtf8InternalEncoding)(void) -{ - return &ns(internal_utf8_encoding).enc; -} - -const ENCODING * -NS(XmlGetUtf16InternalEncoding)(void) -{ -#if BYTEORDER == 1234 - return &ns(internal_little2_encoding).enc; -#elif BYTEORDER == 4321 - return &ns(internal_big2_encoding).enc; -#else - const short n = 1; - return (*(const char *)&n - ? &ns(internal_little2_encoding).enc - : &ns(internal_big2_encoding).enc); -#endif -} - -static const ENCODING * const NS(encodings)[] = { - &ns(latin1_encoding).enc, - &ns(ascii_encoding).enc, - &ns(utf8_encoding).enc, - &ns(big2_encoding).enc, - &ns(big2_encoding).enc, - &ns(little2_encoding).enc, - &ns(utf8_encoding).enc /* NO_ENC */ -}; - -static int PTRCALL -NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - return initScan(NS(encodings), (const INIT_ENCODING *)enc, - XML_PROLOG_STATE, ptr, end, nextTokPtr); -} - -static int PTRCALL -NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end, - const char **nextTokPtr) -{ - return initScan(NS(encodings), (const INIT_ENCODING *)enc, - XML_CONTENT_STATE, ptr, end, nextTokPtr); -} - -int -NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr, - const char *name) -{ - int i = getEncodingIndex(name); - if (i == UNKNOWN_ENC) - return 0; - SET_INIT_ENC_INDEX(p, i); - p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog); - p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent); - p->initEnc.updatePosition = initUpdatePosition; - p->encPtr = encPtr; - *encPtr = &(p->initEnc); - return 1; -} - -static const ENCODING * -NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) -{ -#define ENCODING_MAX 128 - char buf[ENCODING_MAX]; - char *p = buf; - int i; - XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); - if (ptr != end) - return 0; - *p = 0; - if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2) - return enc; - i = getEncodingIndex(buf); - if (i == UNKNOWN_ENC) - return 0; - return NS(encodings)[i]; -} - -int -NS(XmlParseXmlDecl)(int isGeneralTextEntity, - const ENCODING *enc, - const char *ptr, - const char *end, - const char **badPtr, - const char **versionPtr, - const char **versionEndPtr, - const char **encodingName, - const ENCODING **encoding, - int *standalone) -{ - return doParseXmlDecl(NS(findEncoding), - isGeneralTextEntity, - enc, - ptr, - end, - badPtr, - versionPtr, - versionEndPtr, - encodingName, - encoding, - standalone); -} - -#endif /* XML_TOK_NS_C */ diff -Nru simgear-2.10.0/version simgear-3.0.0/version --- simgear-2.10.0/version 2013-02-18 14:58:14.000000000 +0000 +++ simgear-3.0.0/version 2014-02-15 00:04:11.000000000 +0000 @@ -1 +1 @@ -2.10.0 +3.0.0