(root)/
libredwg-0.13/
src/
common.c
       1  /*****************************************************************************/
       2  /*  LibreDWG - free implementation of the DWG file format                    */
       3  /*                                                                           */
       4  /*  Copyright (C) 2009-2023 Free Software Foundation, Inc.                   */
       5  /*                                                                           */
       6  /*  This library is free software, licensed under the terms of the GNU       */
       7  /*  General Public License as published by the Free Software Foundation,     */
       8  /*  either version 3 of the License, or (at your option) any later version.  */
       9  /*  You should have received a copy of the GNU General Public License        */
      10  /*  along with this program.  If not, see <http://www.gnu.org/licenses/>.    */
      11  /*****************************************************************************/
      12  
      13  /*
      14   * common.c: common data arrays
      15   * written by Felipe Castro
      16   * modified by Felipe CorrĂȘa da Silva Sances
      17   * modified by Rodrigo Rodrigues da Silva
      18   * modified by Reini Urban
      19   */
      20  
      21  #include "config.h"
      22  #define COMMON_C
      23  #include <stdio.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include <assert.h>
      27  #include <time.h>
      28  #include <math.h>
      29  #include <ctype.h>
      30  #include "common.h"
      31  #include "logging.h"
      32  
      33  // See also
      34  // http://devel.gvsig.org/sites/org.gvsig.dwg/2.0-SNAPSHOT/gvsig-base-library-pom/org.gvsig.dwg/xref/org/gvsig/dwg/lib/DwgFile.html
      35  const struct dwg_versions dwg_versions[] = {
      36    /* r,          type,    hdr,    desc,         dwg_version */
      37    { R_INVALID, "invalid", "INVALI", "No DWG", 0 },
      38    { R_1_1, "r1.1", "MC0.0", "MicroCAD Release 1.1", 0 },
      39    { R_1_2, "r1.2", "AC1.2", "AutoCAD Release 1.2", 0 },
      40    { R_1_3, "r1.3", "AC1.3", "AutoCAD Release 1.3", 1 },
      41    { R_1_4, "r1.4", "AC1.40", "AutoCAD Release 1.4", 2 },
      42    { R_2_0b, "r2.0b", "AC1.50", "AutoCAD 2.0 beta", 3 }, // not seen
      43    { R_2_0, "r2.0", "AC1.50", "AutoCAD Release 2.0", 4 },
      44    { R_2_10, "r2.10", "AC2.10", "AutoCAD Release 2.10", 5 },
      45    { R_2_21, "r2.21", "AC2.21", "AutoCAD Release 2.21", 6 },
      46    { R_2_22, "r2.22", "AC2.22", "AutoCAD Release 2.22", 7 },
      47    { R_2_4, "r2.4", "AC1001", "AutoCAD Release 2.4", 8 },
      48    { R_2_5, "r2.5", "AC1002", "AutoCAD Release 2.5", 9 },
      49    { R_2_6, "r2.6", "AC1003", "AutoCAD Release 2.6", 10 },
      50    { R_9, "r9", "AC1004", "AutoCAD Release 9", 0xb },
      51    { R_9c1, "r9c1", "AC1005", "AutoCAD Release 9c1", 0xc },
      52    { R_10, "r10", "AC1006", "AutoCAD Release 10", 0xd },
      53    { R_11b1, "r11b1", "AC1007", "AutoCAD 11 beta 1", 0xe },
      54    { R_11b2, "r11b2", "AC1008", "AutoCAD 11 beta 2", 0xf },
      55    { R_11, "r11", "AC1009", "AutoCAD Release 11/12 (LT R1/R2)", 0x10 },
      56    { R_13b1, "r13b1", "AC1010", "AutoCAD pre-R13 a", 0x11 },
      57    { R_13b2, "r13b2", "AC1011", "AutoCAD pre-R13 b", 0x12 },
      58    { R_13, "r13", "AC1012", "AutoCAD Release 13", 0x13 },
      59    { R_13c3, "r13c3", "AC1013", "AutoCAD Release 13c3", 0x14 },
      60    { R_14, "r14", "AC1014", "AutoCAD Release 14", 0x15 },
      61    { R_2000b, "r2000b", "AC1500", "AutoCAD 2000 beta", 0x16 },
      62    { R_2000, "r2000", "AC1015", "AutoCAD Release 2000", 0x17 },
      63    { R_2000i, "r2000i", "AC1016", "AutoCAD Release 2000i", 0x17 },
      64    { R_2002, "r2002", "AC1017", "AutoCAD Release 2002", 0x17 },
      65    { R_2004a, "r2004a", "AC402a", "AutoCAD 2004 alpha a", 0x18 },
      66    { R_2004b, "r2004b", "AC402b", "AutoCAD 2004 alpha b", 0x18 },
      67    { R_2004c, "r2004c", "AC1018", "AutoCAD 2004 beta", 0x18 },
      68    // (includes versions AC1019/0x19 and AC1020/0x1a)
      69    { R_2004, "r2004", "AC1018", "AutoCAD Release 2004", 0x19 },
      70    //{ R_2005, "r2005", "AC1019", "AutoCAD 2005", 0x19 }, // not seen
      71    //{ R_2006, "r2006", "AC1020", "AutoCAD 2006", 0x19 }, // not seen
      72    { R_2007a, "r2007a", "AC701a", "AutoCAD 2007 alpha", 0x1a },
      73    { R_2007b, "r2007b", "AC1021", "AutoCAD 2007 beta", 0x1a },
      74    { R_2007, "r2007", "AC1021", "AutoCAD Release 2007", 0x1b },
      75    //{ R_2008, "r2008", "AC1022", "AutoCAD 2008", 0x1b }, // not seen
      76    //{ R_2009, "r2009", "AC1023", "AutoCAD 2009", 0x1b }, // not seen
      77    { R_2010b, "r2010b", "AC1024", "AutoCAD 2010 beta", 0x1c },
      78    { R_2010, "r2010", "AC1024", "AutoCAD Release 2010", 0x1d },
      79    //{ R_2011, "r2011", "AC1025", "AutoCAD 2011", 0x1d }, // not seen
      80    //{ R_2012, "r2012", "AC1026", "AutoCAD 2012", 0x1e }, // not seen
      81    { R_2013b, "r2013b", "AC1027", "AutoCAD 2013 beta", 0x1e },
      82    { R_2013, "r2013", "AC1027", "AutoCAD Release 2013", 0x1f },
      83    //{ R_2014, "r2014", "AC1028", "AutoCAD 2014", 0x1f }, // not seen
      84    //{ R_2015, "r2015", "AC1029", "AutoCAD 2015", 0x1f }, // not seen
      85    //{ R_2016, "r2016", "AC1030", "AutoCAD 2016", 0x1f }, // not seen
      86    //{ R_2017, "r2017", "AC1031", "AutoCAD 2017", 0x20 }, // not seen
      87    { R_2018b, "r2018b", "AC1032", "AutoCAD 2018 beta", 0x20 },
      88    { R_2018, "r2018", "AC1032", "AutoCAD Release 2018", 0x21 },
      89    //{ R_2019, "r2019", "AC1033", "AutoCAD Release 2019", 0x22 }, // not seen
      90    //{ R_2020, "r2020", "AC1034", "AutoCAD Release 2020", 0x23 }, // not seen
      91    //{ R_2021, "r2021", "AC1035", "AutoCAD Release 2021", 0x23 }, // not seen
      92    { R_2022b, "r2022b", "AC103-4", "AutoCAD 2022 beta", 0x24 },
      93    { R_AFTER, "r>2022", NULL, "AutoCAD Release >2022", 0 },
      94  };
      95  
      96  const unsigned char *
      97  dwg_sentinel (const Dwg_Sentinel sentinel_id)
      98  {
      99    static const unsigned char sentinels[DWG_SENTINEL_R11_AUXHEADER_END + 2][16]
     100        = { // DWG_SENTINEL_HEADER_END
     101            { 0x95, 0xA0, 0x4E, 0x28, 0x99, 0x82, 0x1A, 0xE5, 0x5E, 0x41, 0xE0,
     102              0x5F, 0x9D, 0x3A, 0x4D, 0x00 },
     103            // DWG_SENTINEL_THUMBNAIL_BEGIN
     104            { 0x1F, 0x25, 0x6D, 0x07, 0xD4, 0x36, 0x28, 0x28, 0x9D, 0x57, 0xCA,
     105              0x3F, 0x9D, 0x44, 0x10, 0x2B },
     106            // DWG_SENTINEL_THUMBNAIL_END
     107            { 0xE0, 0xDA, 0x92, 0xF8, 0x2B, 0xc9, 0xD7, 0xD7, 0x62, 0xA8, 0x35,
     108              0xC0, 0x62, 0xBB, 0xEF, 0xD4 },
     109            // DWG_SENTINEL_VARIABLE_BEGIN
     110            { 0xCF, 0x7B, 0x1F, 0x23, 0xFD, 0xDE, 0x38, 0xA9, 0x5F, 0x7C, 0x68,
     111              0xB8, 0x4E, 0x6D, 0x33, 0x5F },
     112            // DWG_SENTINEL_VARIABLE_END
     113            { 0x30, 0x84, 0xE0, 0xDC, 0x02, 0x21, 0xC7, 0x56, 0xA0, 0x83, 0x97,
     114              0x47, 0xB1, 0x92, 0xCC, 0xA0 },
     115            // DWG_SENTINEL_CLASS_BEGIN
     116            { 0x8D, 0xA1, 0xC4, 0xB8, 0xC4, 0xA9, 0xF8, 0xC5, 0xC0, 0xDC, 0xF4,
     117              0x5F, 0xE7, 0xCF, 0xB6, 0x8A },
     118            // DWG_SENTINEL_CLASS_END
     119            { 0x72, 0x5E, 0x3B, 0x47, 0x3B, 0x56, 0x07, 0x3A, 0x3F, 0x23, 0x0B,
     120              0xA0, 0x18, 0x30, 0x49, 0x75 },
     121            // DWG_SENTINEL_2NDHEADER_BEGIN
     122            { 0xD4, 0x7B, 0x21, 0xCE, 0x28, 0x93, 0x9F, 0xBF, 0x53, 0x24, 0x40,
     123              0x09, 0x12, 0x3C, 0xAA, 0x01 },
     124            // DWG_SENTINEL_2NDHEADER_END
     125            { 0x2B, 0x84, 0xDE, 0x31, 0xD7, 0x6C, 0x60, 0x40, 0xAC, 0xDB, 0xBF,
     126              0xF6, 0xED, 0xC3, 0x55, 0xFE },
     127            // DWG_SENTINEL_R11_ENTITIES_BEGIN C46E6854F86E3330633EC1852ADC9401
     128            { 0xC4, 0x6E, 0x68, 0x54, 0xF8, 0x6E, 0x33, 0x30, 0x63, 0x3E, 0xC1,
     129              0x85, 0x2A, 0xDC, 0x94, 0x01 },
     130            // DWG_SENTINEL_R11_ENTITIES_END   3B9197AB0791CCCF9CC13E7AD5236BFE
     131            { 0x3B, 0x91, 0x97, 0xAB, 0x07, 0x91, 0xCC, 0xCF, 0x9C, 0xC1, 0x3E,
     132              0x7A, 0xD5, 0x23, 0x6B, 0xFE },
     133            // DWG_SENTINEL_R11_BLOCK_BEGIN DBEFB3F0C73E6DA6C9B6245C4C6F32CB
     134            { 0xDB, 0xEF, 0xB3, 0xF0, 0xC7, 0x3E, 0x6D, 0xA6, 0xC9, 0xB6, 0x24,
     135              0x5C, 0x4C, 0x6F, 0x32, 0xCB },
     136            // DWG_SENTINEL_R11_BLOCK_END   24104C0F38C192593649DBA3B390CD34
     137            { 0x24, 0x10, 0x4C, 0x0F, 0x38, 0xC1, 0x92, 0x59, 0x36, 0x49, 0xDB,
     138              0xA3, 0xB3, 0x90, 0xCD, 0x34 },
     139            // DWG_SENTINEL_R11_LAYER_BEGIN 0EC4646FBB1DD38B0049C2EF18EA6FFB
     140            { 0x0E, 0xC4, 0x64, 0x6F, 0xBB, 0x1D, 0xD3, 0x8B, 0x00, 0x49, 0xC2,
     141              0xEF, 0x18, 0xEA, 0x6F, 0xFB },
     142            // DWG_SENTINEL_R11_LAYER_END   F13B9B9044E22C74FFB63D10E7159004
     143            { 0xF1, 0x3B, 0x9B, 0x90, 0x44, 0xE2, 0x2C, 0x74, 0xFF, 0xB6, 0x3D,
     144              0x10, 0xE7, 0x15, 0x90, 0x04 },
     145            // DWG_SENTINEL_R11_STYLE_BEGIN E23EC182439F617750ABC76696000618
     146            { 0xE2, 0x3E, 0xC1, 0x82, 0x43, 0x9F, 0x61, 0x77, 0x50, 0xAB, 0xC7,
     147              0x66, 0x96, 0x00, 0x06, 0x18 },
     148            // DWG_SENTINEL_R11_STYLE_END   1DC13E7DBC609E88AF54389969FFF9E7
     149            { 0x1D, 0xC1, 0x3E, 0x7D, 0xBC, 0x60, 0x9E, 0x88, 0xAF, 0x54, 0x38,
     150              0x99, 0x69, 0xFF, 0xF9, 0xE7 },
     151            // DWG_SENTINEL_R11_LTYPE_BEGIN AC901ACA1CBD951516164C14CE1888AF
     152            { 0xAC, 0x90, 0x1A, 0xCA, 0x1C, 0xBD, 0x95, 0x15, 0x16, 0x16, 0x4C,
     153              0x14, 0xCE, 0x18, 0x88, 0xAF },
     154            // DWG_SENTINEL_R11_LTYPE_END   536FE535E3426AEAE9E9B3EB31E77750
     155            { 0x53, 0x6F, 0xE5, 0x35, 0xE3, 0x42, 0x6A, 0xEA, 0xE9, 0xE9, 0xB3,
     156              0xEB, 0x31, 0xE7, 0x77, 0x50 },
     157            // DWG_SENTINEL_R11_VIEW_BEGIN  C13CAA5668F4B41E4B74F408424DBFA5
     158            { 0xC1, 0x3C, 0xAA, 0x56, 0x68, 0xF4, 0xB4, 0x1E, 0x4B, 0x74, 0xF4,
     159              0x08, 0x42, 0x4D, 0xBF, 0xA5 },
     160            // DWG_SENTINEL_R11_VIEW_END    3EC355A9970B4BE1B48B0BF7BDB2405A
     161            { 0x3E, 0xC3, 0x55, 0xA9, 0x97, 0x0B, 0x4B, 0xE1, 0xB4, 0x8B, 0x0B,
     162              0xF7, 0xBD, 0xB2, 0x40, 0x5A },
     163            // DWG_SENTINEL_R11_UCS_BEGIN   604AFA3D8490CC5BEFE7D6A57F1E61CD
     164            { 0x60, 0x4A, 0xFA, 0x3D, 0x84, 0x90, 0xCC, 0x5B, 0xEF, 0xE7, 0xD6,
     165              0xA5, 0x7F, 0x1E, 0x61, 0xCD },
     166            // DWG_SENTINEL_R11_UCS_END     9FB505C27B6F33A41018295A80E19E32
     167            { 0x9F, 0xB5, 0x05, 0xC2, 0x7B, 0x6F, 0x33, 0xA4, 0x10, 0x18, 0x29,
     168              0x5A, 0x80, 0xE1, 0x9E, 0x32 },
     169            // DWG_SENTINEL_R11_VPORT_BEGIN F6ED44612ADCE47B4EB92BBB6660638D
     170            { 0xF6, 0xED, 0x44, 0x61, 0x2A, 0xDC, 0xE4, 0x7B, 0x4E, 0xB9, 0x2B,
     171              0xBB, 0x66, 0x60, 0x63, 0x8D },
     172            // DWG_SENTINEL_R11_VPORT_END   0912BB9ED5231B84B146D444999F9C72
     173            { 0x09, 0x12, 0xBB, 0x9E, 0xD5, 0x23, 0x1B, 0x84, 0xB1, 0x46, 0xD4,
     174              0x44, 0x99, 0x9F, 0x9C, 0x72 },
     175            // DWG_SENTINEL_R11_APPID_BEGIN E125C25036686C0C3BD35D56C1791C3A
     176            { 0xE1, 0x25, 0xC2, 0x50, 0x36, 0x68, 0x6C, 0x0C, 0x3B, 0xD3, 0x5D,
     177              0x56, 0xC1, 0x79, 0x1C, 0x3A },
     178            // DWG_SENTINEL_R11_APPID_END   1EDA3DAFC99793F3C42CA2A93E86E3C5
     179            { 0x1E, 0xDA, 0x3D, 0xAF, 0xC9, 0x97, 0x93, 0xF3, 0xC4, 0x2C, 0xA2,
     180              0xA9, 0x3E, 0x86, 0xE3, 0xC5 },
     181            // DWG_SENTINEL_R11_DIMSTYLE_BEGIN B4183E42C99FFFE5B6E2CBB375C3C3B0
     182            { 0xB4, 0x18, 0x3E, 0x42, 0xC9, 0x9F, 0xFF, 0xE5, 0xB6, 0xE2, 0xCB,
     183              0xB3, 0x75, 0xC3, 0xC3, 0xB0 },
     184            // DWG_SENTINEL_R11_DIMSTYLE_END   4BE7C1BD3660001A491D344C8A3C3C4F
     185            { 0x4B, 0xE7, 0xC1, 0xBD, 0x36, 0x60, 0x00, 0x1A, 0x49, 0x1D, 0x34,
     186              0x4C, 0x8A, 0x3C, 0x3C, 0x4F },
     187            // DWG_SENTINEL_R11_VX_BEGIN    E0CA367CCEE7586F2B7D745505F1447F
     188            { 0xE0, 0xCA, 0x36, 0x7C, 0xCE, 0xE7, 0x58, 0x6F, 0x2B, 0x7D, 0x74,
     189              0x55, 0x05, 0xF1, 0x44, 0x7F },
     190            // DWG_SENTINEL_R11_VX_END      1F35C9833118A790D4828BAAFA0EBB80
     191            { 0x1F, 0x35, 0xC9, 0x83, 0x31, 0x18, 0xA7, 0x90, 0xD4, 0x82, 0x8B,
     192              0xAA, 0xFA, 0x0E, 0xBB, 0x80 },
     193            // DWG_SENTINEL_R11_BLOCK_ENTITIES_BEGIN
     194            // 722B7DEC3E8C886C7A720AFDC86C8426
     195            { 0x72, 0x2B, 0x7D, 0xEC, 0x3E, 0x8C, 0x88, 0x6C, 0x7A, 0x72, 0x0A,
     196              0xFD, 0xC8, 0x6C, 0x84, 0x26 },
     197            // DWG_SENTINEL_R11_BLOCK_ENTITIES_END
     198            // 8DD48213C1737793858DF50237937BD9
     199            { 0x8D, 0xD4, 0x82, 0x13, 0xC1, 0x73, 0x77, 0x93, 0x85, 0x8D, 0xF5,
     200              0x02, 0x37, 0x93, 0x7B, 0xD9 },
     201            // DWG_SENTINEL_R11_EXTRA_ENTITIES_BEGIN
     202            // D5F9D3BB0AA969A6CD1C87C7EE804B17
     203            { 0xD5, 0xF9, 0xD3, 0xBB, 0x0A, 0xA9, 0x69, 0xA6, 0xCD, 0x1C, 0x87,
     204              0xC7, 0xEE, 0x80, 0x4B, 0x17 },
     205            // DWG_SENTINEL_R11_EXTRA_ENTITIES_END
     206            // 2A062C44F556965932E37838117FB4E8
     207            { 0x2A, 0x06, 0x2C, 0x44, 0xF5, 0x56, 0x96, 0x59, 0x32, 0xE3, 0x78,
     208              0x38, 0x11, 0x7F, 0xB4, 0xE8 },
     209            // DWG_SENTINEL_R11_AUXHEADER_BEGIN 298DD149A9731FEA99DE32F94D0AE019
     210            { 0x29, 0x8D, 0xD1, 0x49, 0xA9, 0x73, 0x1F, 0xEA, 0x99, 0xDE, 0x32,
     211              0xF9, 0x4D, 0x0A, 0xE0, 0x19 },
     212            // DWG_SENTINEL_R11_AUXHEADER_END D6722EB6568CE0156621CD06B2F51FE6
     213            { 0xD6, 0x72, 0x2E, 0xB6, 0x56, 0x8C, 0xE0, 0x15, 0x66, 0x21, 0xCD,
     214              0x06, 0xB2, 0xF5, 0x1F, 0xE6 },
     215            // DWG_SENTINEL_ILLEGAL (used for memcmp)
     216            { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
     217              0xFE, 0xFE, 0xFE, 0xFE, 0xFE }
     218          };
     219    if ((unsigned)sentinel_id > DWG_SENTINEL_R11_AUXHEADER_END)
     220      {
     221        fprintf (stderr, "ERROR: Illegal sentinel_id %u\n",
     222                 (unsigned)sentinel_id);
     223        return sentinels[DWG_SENTINEL_R11_AUXHEADER_END + 1];
     224      }
     225    return (const unsigned char *)sentinels[sentinel_id];
     226  }
     227  
     228  const struct dwg_versions *
     229  dwg_version_struct (const Dwg_Version_Type version)
     230  {
     231    if (version < R_AFTER)
     232      return &dwg_versions[version];
     233    else
     234      return NULL;
     235  }
     236  
     237  /* Returns the AC header magic string [6] */
     238  const char *
     239  dwg_version_codes (const Dwg_Version_Type version)
     240  {
     241    if (version < R_AFTER)
     242      return dwg_versions[version].hdr;
     243    else
     244      return "------";
     245  }
     246  
     247  // map [rVER] to our enum number, not the dwg->header.dwgversion
     248  // Acad 2018 offers SaveAs DWG: 2018,2013,2010,2007,2004,2000,r14
     249  //                         DXF: 2018,2013,2010,2007,2004,2000,r12
     250  // libdxfrw dwg2dxf offers R12, v2000, v2004, v2007, v2010
     251  EXPORT Dwg_Version_Type
     252  dwg_version_as (const char *version)
     253  {
     254    for (int i = R_AFTER - 1; i > 0; i--)
     255      {
     256        if (strEQ (dwg_versions[i].type, version))
     257          return dwg_versions[i].r;
     258      }
     259    return R_INVALID;
     260  }
     261  
     262  /** The reverse of dwg_version_as (char*) */
     263  EXPORT const char *
     264  dwg_version_type (const Dwg_Version_Type version)
     265  {
     266    if (version < R_AFTER)
     267      return dwg_versions[version].type;
     268    else
     269      return "invalid after";
     270  }
     271  
     272  /** The version from the magic char[6] header.
     273      The proper release must then be set when we read the dwg_version also. */
     274  EXPORT Dwg_Version_Type
     275  dwg_version_hdr_type (const char *hdr)
     276  {
     277    for (int i = R_AFTER - 1; i > 0; i--)
     278      {
     279        if (strEQ (dwg_versions[i].hdr, hdr))
     280          return dwg_versions[i].r;
     281      }
     282    return R_INVALID;
     283  }
     284  
     285  /** The version from the magic char[6] header and the matching dwg_version
     286   * number. */
     287  Dwg_Version_Type
     288  dwg_version_hdr_type2 (const char *hdr, unsigned dwg_version)
     289  {
     290    for (int i = R_AFTER - 1; i > 0; i--)
     291      {
     292        if (strEQ (dwg_versions[i].hdr, hdr))
     293          if (!dwg_version || dwg_versions[i].dwg_version == dwg_version)
     294            return dwg_versions[i].r;
     295      }
     296    return R_INVALID;
     297  }
     298  
     299  // keep in sync with common.h DWG_BITS
     300  const char *dwg_bits_name[]
     301      = { "UNKNOWN", "RC",  "RS",  "RL",  "B",       "BB",  "3B",     "4BITS",
     302          "BS",      "BL",  "BLd", "RLL", "RD",      "BD",  "MC",     "UMC",
     303          "MS",      "TV",  "TU",  "T",   "TF",      "T32", "HANDLE", "BE",
     304          "DD",      "BT",  "BOT", "BLL", "TIMEBLL", "CMC", "ENC",    "2RD",
     305          "3RD",     "2BD", "3BD", "2DD", "3DD",     "CRC", "CRC64",  "RLLd" };
     306  
     307  // minimal size of type in bits
     308  // keep in sync with above
     309  // used by unit-tests
     310  const unsigned char dwg_bits_size[] = {
     311    0,   //"UNKNOWN",
     312    8,   //"RC",
     313    16,  //"RS",
     314    32,  //"RL",
     315    1,   //"B",
     316    2,   //"BB",
     317    3,   //"3B",
     318    4,   //"4BITS",
     319    2,   //"BS", 10,18
     320    2,   //"BL", 10,34
     321    2,   //"BLd", 10,34
     322    64,  //"RLL",
     323    64,  //"RD",
     324    2,   //"BD", 66
     325    1,   //"MC", 1-4
     326    1,   //"UMC", 1-4
     327    16,  //"MS", 32
     328    2,   //"TV",
     329    18,  //"TU",
     330    2,   //"T",
     331    1,   //"TF",
     332    2,   //"T32",
     333    4,   //"TU32",
     334    8,   //"HANDLE",
     335    1,   //"BE", or 3BD
     336    2,   //"DD",
     337    1,   //"BT",
     338    10,  //"BOT",
     339    3,   //"BLL",
     340    4,   //"TIMEBLL", 2xBL
     341    2,   //"CMC", r2004+: +2
     342    4,   //"ENC", r2004+
     343    128, //"2RD",
     344    196, //"3RD",
     345    4,   //"2BD",
     346    6,   //"3BD",
     347    4,   //"2DD",
     348    6,   //"3DD",
     349    8,   //"CRC",
     350    64,  //"CRC64",
     351    64,  //"RLLd",
     352  };
     353  
     354  /* replace from ("[rcount1]") with to ("[%d]") in s (e.g.
     355     "ref[rcount1].classname"). s is a global constant (#nam), so we cannot
     356     change it in-place.
     357   */
     358  EXPORT char *
     359  strrplc (const char *s, const char *from, const char *to)
     360  {
     361    const char *p = strstr (s, from);
     362    if (p)
     363      {
     364        const size_t l1 = strlen (from);
     365        const size_t l2 = strlen (to);
     366        char *dest = (char *)calloc (1, 80);
     367        long i = p - s;
     368        assert (strlen (s) - ((long)l1 - l2) < 80);
     369        memcpy (dest, s, i);
     370        strncat (dest, to, 79 - l2);
     371        strncat (dest, s + i + l1, 79 - l1);
     372        return dest;
     373      }
     374    else
     375      return NULL;
     376  }
     377  
     378  #if !defined(HAVE_MEMMEM) || defined(COMMON_TEST_C)
     379  // naive from scratch implementation, not from glibc.
     380  // see also examples/unknown.c:membits
     381  void *__nonnull ((1, 3))
     382      my_memmem (const void *h0, size_t k, const void *n0, size_t l)
     383  {
     384    const unsigned char *h = h0, *n = n0;
     385    unsigned char *plast;
     386  
     387    if (!l)
     388      return (void *)h; // empty needle
     389    if (k < l)
     390      return NULL; // needle longer than haystack
     391    h = memchr (h0, *n, k);
     392    if (!h || l == 1)
     393      return (void *)h; // first needle char not found
     394    k -= h - (const unsigned char *)h0;
     395    if (k < l)
     396      return NULL; // no room for needle
     397  
     398    plast = (unsigned char *)h + (k - l);
     399    do // naive 2 loops: O(n^2)
     400      {
     401        size_t i = 0;
     402        while (h[i] == n[i])
     403          {
     404            if (++i == l)
     405              return (void *)h;
     406          }
     407      }
     408    while (++h <= plast);
     409    return NULL;
     410  }
     411  #endif
     412  
     413  /*
     414   32 types, with 3 categories: Face, Edge, Display, plus 58 props r2013+
     415   */
     416  const char *const _dwg_VISUALSTYLE_types[32] = { "Flat",
     417                                                   "FlatWithEdges",
     418                                                   "Gouraud",
     419                                                   "GouraudWithEdges",
     420                                                   "2DWireframe",
     421                                                   "3DWireFrame",
     422                                                   "Hidden",
     423                                                   "Basic",
     424                                                   "Realistic",
     425                                                   "Conceptual",
     426                                                   "Dim",
     427                                                   "Brighten",
     428                                                   "Thicken",
     429                                                   "LinePattern",
     430                                                   "Facepattern",
     431                                                   "ColorChange",
     432                                                   "FaceOnly",
     433                                                   "EdgeOnly",
     434                                                   "DisplayOnly",
     435                                                   "JitterOff",
     436                                                   "OverhangOff",
     437                                                   "EdgeColorOff",
     438                                                   "Shades of Gray",
     439                                                   "Sketchy",
     440                                                   "X-Ray",
     441                                                   "Shaded with edges",
     442                                                   "Shaded",
     443                                                   "ByViewport",
     444                                                   "ByLayer",
     445                                                   "ByBlock",
     446                                                   "ForEmptyStyle" };
     447  
     448  /* types of the 58 rest r2013+ properties.
     449   * 1:
     450   * 2:
     451   * 3:
     452   * 4:
     453   * 5:
     454   */
     455  const unsigned char _dwg_VISUALSTYLE_proptypes[58] = {
     456    /* [0]  */ 2, 2, 2, 2,
     457    /* [4]  */ 3, 3, 4, 2,
     458    /* [8]  */ 2, 4, 4, 2,
     459    /* [12] */ 2, 3, 2, 4,
     460    /* [16] */ 3, 2, 2, 2,
     461    /* [20] */ 4, 2, 2, 2,
     462    /* [24] */ 1, 2, 3, 2,
     463    /* [28] */ 1, 1, 1, 1,
     464    /* [32] */ 1, 1, 1, 1,
     465    /* [36] */ 1, 2, 3, 3,
     466    /* [40] */ 2, 4, 2, 2,
     467    /* [44] */ 4, 1, 2, 2,
     468    /* [48] */ 2, 1, 2, 4,
     469    /* [52] */ 3, 2, 5, 1,
     470    /* [56] */ 3, 3
     471  };
     472  
     473  // returns the first ref from the handle vector.
     474  BITCODE_H
     475  shift_hv (BITCODE_H *hv, BITCODE_BL *num_p)
     476  {
     477    BITCODE_H ref = hv[0];
     478    *num_p = *num_p - 1;
     479    memmove (&hv[0], &hv[1], *num_p * sizeof (BITCODE_H));
     480    return ref;
     481  }
     482  
     483  // delete an entry from an HV ("handle vector") at index i
     484  void
     485  delete_hv (BITCODE_H *entries, BITCODE_BS *num_p, BITCODE_BS i)
     486  {
     487    BITCODE_H ref;
     488    BITCODE_BS nume = *num_p;
     489    assert (i < nume);
     490    ref = entries[i];
     491    *num_p = *num_p - 1;
     492    nume--;
     493    if (!ref->handleref.is_global)
     494      free (ref);
     495    if (!nume || i != nume) // not the last?
     496      {
     497        memmove (&entries[i], &entries[i + 1], (nume - i) * sizeof (BITCODE_H));
     498      }
     499  }
     500  
     501  /* from my dwg11.c, 1995 - rurban */
     502  struct tm *
     503  cvt_TIMEBLL (struct tm *tm, BITCODE_TIMEBLL date)
     504  {
     505    double t, ss;
     506    long ja, jalpha, jb, jc, jd, je;
     507  
     508  #define TRUNC(n) (long)floor (n)
     509  
     510    t = 0.864 * date.ms / 1000.0; /*t=1000000 = 1 day, means 86400 in seconds */
     511    if (date.days > 2299161)
     512      {
     513        jalpha = TRUNC (((date.days - 1867216) - 0.25) / 36524.25);
     514        ja = (long)(date.days + 1 + jalpha - TRUNC (0.25 * jalpha));
     515      }
     516    else
     517      ja = (long)date.days;
     518    if (ja < 1000)
     519      {
     520        // TDINDWG: relative minutes
     521        memset (tm, 0, sizeof (struct tm));
     522      }
     523    else
     524      {
     525        jb = ja + 1524;
     526        jc = TRUNC (6680.0 + ((jb - 2439870) - 122.1) / 365.25);
     527        jd = 365 * jc + TRUNC (0.25 * jc);
     528        je = TRUNC ((jb - jd) / 30.6001);
     529  
     530        tm->tm_mday = (int)(jb - jd - TRUNC (30.6001 * je));
     531        if (tm->tm_mday < 1)
     532          tm->tm_mday = 1;
     533        else if (tm->tm_mday > 31)
     534          tm->tm_mday %= 31;
     535        tm->tm_mon = (int)(je - 1);
     536        if (tm->tm_mon > 12)
     537          tm->tm_mon -= 12;
     538        tm->tm_year = (int)(jc - 4715);
     539        if (tm->tm_mon > 2)
     540          tm->tm_year--;
     541        if (tm->tm_year <= 0)
     542          tm->tm_year--;
     543        tm->tm_year -= 1900; // epoch start
     544        tm->tm_mon--;        // zero-based
     545      }
     546    tm->tm_hour = (int)floor (t / 3600.0);
     547    t -= tm->tm_hour * 3600.0;
     548    if (ja >= 1000)
     549      tm->tm_hour = tm->tm_hour % 24;
     550    tm->tm_min = (int)floor (t / 60.0);
     551    ss = t - (tm->tm_min * 60.0);
     552    tm->tm_sec = (int)ss;
     553    // sprintf (s, "%02d.%02d.%4d  %02d:%02d:%05.2f", d, m, y, hh, mm, ss);
     554    return tm;
     555  }
     556  
     557  /* in seconds */
     558  long
     559  tm_offset (void)
     560  {
     561    time_t gmt, rawtime = time (NULL);
     562    struct tm *tm;
     563  
     564  #ifdef HAVE_GMTIME_R
     565    struct tm gbuf;
     566    tm = gmtime_r (&rawtime, &gbuf);
     567  #else
     568    tm = gmtime (&rawtime);
     569  #endif
     570    // Force mktime() lookup dst in timezone database
     571    tm->tm_isdst = -1;
     572    gmt = mktime (tm);
     573    return (long)difftime (rawtime, gmt);
     574  }
     575  
     576  // portability compat funcs
     577  
     578  #ifndef HAVE_STRCASECMP
     579  EXPORT int
     580  strcasecmp (const char *a, const char *b)
     581  {
     582    size_t l2;
     583    int r1 = strcmp (a, b);
     584    if (!r1)
     585      return 0;
     586    l2 = strlen (b);
     587    for (size_t i = 0; i < strlen (a); i++)
     588      {
     589        if (i > l2)
     590          return 1;
     591        if (toupper (a[i]) != toupper (b[i]))
     592          return toupper (a[i]) < toupper (b[i]);
     593      }
     594    return 0;
     595  }
     596  #endif
     597  
     598  #ifdef _MSC_VER
     599  EXPORT char *
     600  basename (char *path)
     601  {
     602    // I've looked at the winsdk basename implementation. It's a clusterfuck,
     603    // because they have 2-byte widechars. We only accept utf-8 paths
     604    char *p = strrchr (path, '/');
     605    if (!p)
     606      p = strrchr (path, '\\');
     607    return p;
     608  }
     609  #endif