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
  
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
  
52
  
53
  
54
  
55
  
56
  
57
  
58
  
59
  
60
  
61
  
62
  
63
  
64
  
65
  
66
  
67
  
68
  
69
  
70
  
71
  
72
  
73
  
74
  
75
  
76
  
77
  
78
  
79
  
80
  
81
  
82
  
83
  
84
  
85
  
86
  
87
  
88
  
89
  
90
  
91
  
92
  
93
  
94
  
95
  
96
  
97
  
98
  
99
  
100
  
101
  
102
  
103
  
104
  
105
  
106
  
107
  
108
  
109
  
110
  
111
  
112
  
113
  
114
  
115
  
116
  
117
  
118
  
119
  
120
  
121
  
122
  
// AutoCAD R13/R14/R2000 DWG file decoder 
// $Id: _Image_DWG.pmod,v 1.1 2002/07/10 20:16:58 nilsson Exp $ 
 
#pike __REAL_VERSION__ 
 
//! This module decodes the thumbnail raster images embedded in AutoCAD DWG files for 
//! AutoCAD version R13, R14 and R2000 (which equals to file version 12, 14 and 15). 
 
static constant start = "\x1F\x25\x6D\x07\xD4\x36\x28\x28\x9D\x57\xCA\x3F\x9D\x44\x10\x2B"; 
 
static inline int read_RL(string data, int pos) { 
  int r; 
  sscanf(data[pos..pos+3], "%-4c", r); 
  return r; 
} 
 
//! Decodes the DWG @[data] into a mapping. 
//! @mapping 
//!   @member int "version" 
//!     The version of the DWG file. One of 12, 14 and 15. 
//!   @member array(string) "bmp" 
//!     An array with the raw BMP data. 
//!   @member array(string) "wmf" 
//!     An array with the raw WMF data. 
//! @endmapping 
//! 
//! @throws 
//!   This functions throws an error when decoding somehow fails. 
mapping __decode(string data) { 
 
  // decode version id 
  if( data[0..3]!="AC10" ) 
    error("Unknown format\n"); 
  int version = (int)data[4..5]; 
  if( !(< 12, 14, 15 >)[version] ) 
    error("Only DWG for AutoCAD R13, R14 and R2000 are supported." 
          " (File id %d)\n", version); 
 
  // Get image data block offset 
  int pos = read_RL(data, 0x0d); 
 
  // Check sentinel 
  if( data[pos..pos+15]!=start ) 
    error("Error while decoding DWG preview. (Corrupt sentinel)\n"); 
  pos += 16; 
 
  // Image data block size 
  pos += 4; 
 
  // Image counter 
  int i = data[pos++]; 
 
  array bmps  = ({}); 
  array wmfs = ({}); 
 
  for(; i; i--) { 
    int(1..3) code = data[pos++]; 
    switch(code) { 
    case 1: 
      int h_start = read_RL(data, pos); 
      pos += 4; 
      int h_size = read_RL(data, pos); 
      pos += 4; 
      //      werror( "%O\n", sizeof(data[h_start..h_start+h_size-1]) ); 
      break; 
 
    case 2: 
      int bmp_start = read_RL(data, pos); 
      pos += 4; 
      int bmp_size = read_RL(data, pos); 
      pos += 4; 
      // For some reason AutoCAD thought it wise to skip the first 
      // 14 bytes of the BMP file. "BM", 4 bytes data size, 4 bytes 
      // reserved and 4 bytes offset to image data. 
      string header = sprintf("BM%-4c\0\0\0\0\0\0\0\0", bmp_size+14); 
      bmps += ({ header+data[bmp_start..bmp_start+bmp_size-1] }); 
      break; 
 
    case 3: 
      int wmf_start = read_RL(data, pos); 
      pos += 4; 
      int wmf_size = read_RL(data, pos); 
      pos += 4; 
      wmfs += ({ data[wmf_start..wmf_start+wmf_size-1] }); 
      break; 
 
    default: 
      error("Error while decoding DWG preview. (Unknown code %d)\n", code); 
    } 
  } 
 
  return ([ "version" : version, 
            "bmp" : bmps, 
            "wmf" : wmfs ]); 
} 
 
//! API function. Returns a mapping which maps "image" 
//! to the result of decode(data). 
//! @code{ 
//!   return ([ "image":decode(data) ]); 
//! @} 
mapping _decode(string data) { 
  return ([ "image":decode(data) ]); 
} 
 
//! Returns the first successfully decoded bitmap. 
//! @throws 
//!   If no preview was stored, or no preview could 
//!   be decoded an error is thrown. 
Image.Image decode(string data) { 
  mapping res = __decode(data); 
  if( !sizeof(res->bmp) ) 
    error("No bitmap previews available.\n"); 
  foreach(res->bmp, string bmp) { 
    catch { 
      return Image.BMP.decode(bmp); 
    }; 
  } 
  error("Failed to decode any of the previews.\n"); 
}