MSWSP: add parse_CRowsetProperties()
[wireshark-wip.git] / epan / dissectors / packet-mswsp.c
blob73000c43a448210f0dd04be8e95bb54a7829f8b7
1 /* packet-mswsp.c
2 * Routines for PROTONAME dissection
3 * Copyright 2012, Gregor Beck <gregor.beck@sernet.de>
5 * $Id$
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
30 /* Include only as needed */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdbool.h>
36 #include <glib.h>
38 #include <epan/packet.h>
39 #include <epan/prefs.h>
41 #include "packet-smb.h"
42 #include "packet-smb2.h"
44 /* IF PROTO exposes code to other dissectors, then it must be exported
45 in a header file. If not, a header file is not needed at all. */
47 * #include "packet-mswsp.h"
49 #include "mswsp.h"
51 #define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
53 /* Forward declaration we need below (if using proto_reg_handoff...
54 as a prefs callback) */
55 void proto_reg_handoff_mswsp(void);
57 /* Initialize the protocol and registered fields */
58 static int proto_mswsp = -1;
59 static int hf_mswsp_msg = -1;
60 static int hf_mswsp_hdr = -1;
61 static int hf_mswsp_hdr_msg = -1;
62 static int hf_mswsp_hdr_status = -1;
63 static int hf_mswsp_hdr_checksum = -1;
64 static int hf_mswsp_hdr_reserved = -1;
65 static int hf_mswsp_msg_Connect_Version = -1;
66 static int hf_mswsp_msg_ConnectIn_ClientIsRemote = -1;
67 static int hf_mswsp_msg_ConnectIn_Blob1 = -1;
68 static int hf_mswsp_msg_ConnectIn_Blob2 = -1;
69 static int hf_mswsp_msg_ConnectIn_MachineName = -1;
70 static int hf_mswsp_msg_ConnectIn_UserName = -1;
71 static int hf_mswsp_msg_ConnectIn_PropSets_num = -1;
72 static int hf_mswsp_msg_ConnectIn_ExtPropSets_num = -1;
75 /* Global sample preference ("controls" display of numbers) */
76 static gboolean gPREF_HEX = FALSE;
77 /* Global sample port pref */
78 static guint gPORT_PREF = 1234;
80 /* Initialize the subtree pointers */
81 static gint ett_mswsp = -1;
82 static gint ett_mswsp_hdr = -1;
83 static gint ett_mswsp_msg = -1;
84 static gint ett_mswsp_pad = -1;
86 static gint ett_mswsp_property_restriction = -1;
87 static gint ett_CRestrictionArray = -1;
88 static gint ett_CBaseStorageVariant = -1;
89 static gint ett_CBaseStorageVariant_Vector = -1;
90 static gint ett_CBaseStorageVariant_Array = -1;
91 static gint ett_CDbColId = -1;
92 static gint ett_GUID = -1;
93 static gint ett_CDbProp = -1;
94 static gint ett_CDbPropSet = -1;
95 static gint ett_CDbPropSet_Array = -1;
96 static gint ett_CRestriction = -1;
97 static gint ett_CNodeRestriction = -1;
98 static gint ett_CPropertyRestriction = -1;
99 static gint ett_CCoercionRestriction = -1;
100 static gint ett_CContentRestriction = -1;
101 static gint ett_RANGEBOUNDARY = -1;
102 static gint ett_CRangeCategSpec = -1;
103 static gint ett_CCategSpec = -1;
104 static gint ett_CAggregSpec = -1;
105 static gint ett_CAggregSet = -1;
106 static gint ett_CCategorizationSpec = -1;
107 static gint ett_CAggregSortKey = -1;
108 static gint ett_CSortAggregSet = -1;
109 static gint ett_CInGroupSortAggregSet = -1;
110 static gint ett_CInGroupSortAggregSets = -1;
111 static gint ett_CRowsetProperties = -1;
113 static int parse_padding(tvbuff_t *tvb, int offset, int alignment, proto_tree *pad_tree, const char *fmt, ...)
115 if (offset % alignment) {
116 const int padding = alignment - (offset % alignment);
117 va_list ap;
118 proto_item *ti;
119 va_start(ap, fmt);
120 ti = proto_tree_add_text_valist(pad_tree, tvb, offset, padding, fmt, ap);
121 va_end(ap);
123 proto_item_append_text(ti, " (%d)", padding);
124 offset += padding;
126 DISSECTOR_ASSERT((offset % alignment) == 0);
127 return offset;
130 static int parse_guid(tvbuff_t *tvb, int offset, proto_tree *tree, e_guid_t *guid, const char *text)
132 const char *guid_str, *name, *bytes;
133 proto_tree *tr;
134 proto_item *ti;
136 tvb_get_letohguid(tvb, offset, guid);
137 guid_str = guid_to_str(guid);
138 name = guids_get_guid_name(guid);
140 ti = proto_tree_add_text(tree, tvb, offset, 16, "%s: %s {%s}", text, name ? name : "", guid_str);
141 tr = proto_item_add_subtree(ti, ett_GUID);
143 proto_tree_add_text(tr, tvb, offset, 4, "time-low: 0x%08x", guid->data1);
144 offset += 4;
145 proto_tree_add_text(tr, tvb, offset, 2, "time-mid: 0x%04x", guid->data2);
146 offset += 2;
147 proto_tree_add_text(tr, tvb, offset, 2, "time-high-and-version: 0x%04x", guid->data3);
148 offset += 2;
149 proto_tree_add_text(tr, tvb, offset, 1, "clock_seq_hi_and_reserved: 0x%02x", guid->data4[0]);
150 offset += 1;
151 proto_tree_add_text(tr, tvb, offset, 1, "clock_seq_low: 0x%02x", guid->data4[1]);
152 offset += 1;
153 bytes = bytestring_to_str(&guid->data4[2], 6, ':');
154 proto_tree_add_text(tr, tvb, offset, 6, "node: %s", bytes);
155 offset += 6;
157 return offset;
160 /*****************************************************************************************/
161 /* 2.2.1.1 CBaseStorageVariant */
162 static int parse_CBaseStorageVariant(tvbuff_t *tvb, int offset, proto_tree *parent_tree, proto_tree *pad_tree,
163 struct CBaseStorageVariant *value, const char *text);
165 /* 2.2.1.2 CFullPropSpec */
166 static int parse_CFullPropSpec(tvbuff_t *tvb, int offset, proto_tree *tree, proto_tree *pad_tree,
167 struct CFullPropSpec *v);
169 /* 2.2.1.3 CContentRestriction */
170 static int parse_CContentRestriction(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
171 proto_tree *pad_tree, struct CContentRestriction *v,
172 const char *fmt, ...);
173 /* 2.2.1.6 CNodeRestriction */
174 static int parse_CNodeRestriction(tvbuff_t *tvb, int offset, proto_tree *tree, proto_tree *pad_tree,
175 struct CNodeRestriction *v, const char* fmt, ...);
177 /* 2.2.1.7 CPropertyRestriction */
178 static int parse_CPropertyRestriction(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
179 proto_tree *pad_tree, struct CPropertyRestriction *v,
180 const char *fmt, ...);
182 /* 2.2.1.8 CReuseWhere */
183 static int parse_CReuseWhere(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
184 proto_tree *pad_tree _U_, struct CReuseWhere *v,
185 const char *fmt, ...);
187 /* 2.2.1.12 CCoercionRestriction */
188 static int parse_CCoercionRestriction(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
189 proto_tree *pad_tree, struct CCoercionRestriction *v,
190 const char *fmt, ...);
192 /* 2.2.1.17 CRestriction */
193 static int parse_CRestriction(tvbuff_t *tvb, int offset, proto_tree *parent_tree, proto_tree *pad_tree,
194 struct CRestriction *v, const char *fmt, ...);
196 /* 2.2.1.18 CColumnSet */
197 static int parse_CColumnSet(tvbuff_t *tvb, int offset, proto_tree *tree, const char *fmt, ...);
199 /* 2.2.1.20 CCategorizationSpec */
200 static int parse_CCategorizationSpec(tvbuff_t *tvb, int offset,
201 proto_tree *parent_tree, proto_tree *pad_tree,
202 const char *fmt, ...);
204 /* 2.2.1.21 CCategSpec */
205 static int parse_CCategSpec(tvbuff_t *tvb, int offset,
206 proto_tree *parent_tree, proto_tree *pad_tree,
207 const char *fmt, ...);
209 /* 2.2.1.22 CRangeCategSpec */
210 static int parse_CRangeCategSpec(tvbuff_t *tvb, int offset,
211 proto_tree *parent_tree, proto_tree *pad_tree,
212 const char *fmt, ...);
214 /* 2.2.1.23 RANGEBOUNDARY */
215 static int parse_RANGEBOUNDARY(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
216 proto_tree *pad_tree, const char *fmt, ...);
218 /* 2.2.1.24 CAggregSet */
219 static int parse_CAggregSet(tvbuff_t *tvb, int offset,
220 proto_tree *parent_tree, proto_tree *pad_tree,
221 const char *fmt, ...);
223 /* 2.2.1.25 CAggregSpec */
224 static int parse_CAggregSpec(tvbuff_t *tvb, int offset,
225 proto_tree *parent_tree, proto_tree *pad_tree,
226 const char *fmt, ...);
228 /* 2.2.1.26 CSortAggregSet */
229 static int parse_CSortAggregSet(tvbuff_t *tvb, int offset,
230 proto_tree *parent_tree, proto_tree *pad_tree,
231 const char *fmt, ...);
233 /* 2.2.1.27 CAggregSortKey */
234 static int parse_CAggregSortKey(tvbuff_t *tvb, int offset,
235 proto_tree *parent_tree, proto_tree *pad_tree,
236 const char *fmt, ...);
238 /* 2.2.1.28 CInGroupSortAggregSets */
239 static int parse_CInGroupSortAggregSets(tvbuff_t *tvb, int offset,
240 proto_tree *parent_tree, proto_tree *pad_tree,
241 const char *fmt, ...);
243 /* 2.2.1.29 CInGroupSortAggregSet */
244 static int parse_CInGroupSortAggregSet(tvbuff_t *tvb, int offset,
245 proto_tree *parent_tree, proto_tree *pad_tree,
246 const char *fmt, ...);
247 /* 2.2.1.30 CDbColId */
248 static int parse_CDbColId(tvbuff_t *tvb, int offset,
249 proto_tree *parent_tree, proto_tree *pad_tree, const char *text);
251 /* 2.2.1.31 CDbProp */
252 struct GuidPropertySet;
253 static int parse_CDbProp(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
254 proto_tree *pad_tree, struct GuidPropertySet *propset,
255 const char *fmt, ...);
257 /* 2.2.1.32 CDbPropSet */
258 static int parse_CDbPropSet(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
259 proto_tree *pad_tree, const char *fmt, ...);
261 /* 2.2.1.41 CRowsetProperties */
262 static int parse_CRowsetProperties(tvbuff_t *tvb, int offset,
263 proto_tree *parent_tree, proto_tree *pad_tree,
264 const char *fmt, ...);
268 2.2.1.4 CInternalPropertyRestriction
269 2.2.1.5 CNatLanguageRestriction
270 2.2.1.9 CScopeRestriction
271 2.2.1.10 CSort
272 2.2.1.11 CVectorRestriction
273 2.2.1.13 CRelDocRestriction
274 2.2.1.14 CProbRestriction
275 2.2.1.15 CFeedbackRestriction
276 2.2.1.16 CRestrictionArray
277 2.2.1.19 CCategorizationSet
278 2.2.1.33 CPidMapper
279 2.2.1.34 CColumnGroupArray
280 2.2.1.35 CColumnGroup
281 2.2.1.36 SProperty
282 2.2.1.37 CRowSeekAt
283 2.2.1.38 CRowSeekAtRatio
284 2.2.1.39 CRowSeekByBookmark
285 2.2.1.40 CRowSeekNext
286 2.2.1.42 CRowVariant
287 2.2.1.43 CSortSet
288 2.2.1.44 CTableColumn
289 2.2.1.45 SERIALIZEDPROPERTYVALUE
290 2.2.1.46 CCompletionCategSp
294 static int parse_CFullPropSpec(tvbuff_t *tvb, int offset, proto_tree *tree, proto_tree *pad_tree,
295 struct CFullPropSpec *v)
297 static const value_string KIND[] = {
298 {0, "PRSPEC_LPWSTR"},
299 {1, "PRSPEC_PROPID"},
300 {0, NULL}
302 const char *guid_str;
303 proto_item *tree_item = proto_tree_get_parent(tree);
305 offset = parse_padding(tvb, offset, 8, pad_tree, "paddingPropSet");
307 offset = parse_guid(tvb, offset, tree, &v->guid, "GUID");
308 guid_str = guids_resolve_guid_to_str(&v->guid );
309 proto_item_append_text(tree_item, " {%s}", guid_str);
311 v->kind = tvb_get_letohl(tvb, offset);
312 proto_tree_add_text(tree, tvb, offset, 4, "ulKind: %s ", val_to_str(v->kind, KIND, "(Unknown: 0x%x)"));
313 offset += 4;
315 v->u.propid = tvb_get_letohl(tvb, offset);
316 proto_tree_add_text(tree, tvb, offset, 4, "propid: %u ", v->u.propid);
317 offset += 4;
319 if (v->kind == PRSPEC_LPWSTR) {
320 int len = 2*v->u.propid;
321 v->u.name = tvb_get_unicode_string(tvb, offset, len, ENC_LITTLE_ENDIAN);
322 proto_tree_add_text(tree, tvb, offset, len, "name: \"%s\"", v->u.name);
323 proto_item_append_text(tree_item, " \"%s\"", v->u.name);
324 offset += len;
325 } else if (v->kind == PRSPEC_PROPID) {
326 proto_item_append_text(tree_item, " 0x%08x", v->u.propid);
327 } else {
328 proto_item_append_text(tree_item, "<INVALID>");
330 return offset;
335 static const value_string PR_VALS[] = {
336 {PRLT, "PRLT"},
337 {PRLE, "PRLE"},
338 {PRGT, "PRGT"},
339 {PRGE, "PRGE"},
340 {PREQ, "PREQ"},
341 {PRNE, "PRNE"},
342 {PRRE, "PRRE"},
343 {PRAllBits, "PRAllBits"},
344 {PRSomeBits, "PRSomeBits"},
345 {PRAll, "PRAll"},
346 {PRSome, "PRSome"},
350 static int parse_CPropertyRestriction(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
351 proto_tree *pad_tree, struct CPropertyRestriction *v,
352 const char *fmt, ...)
354 proto_tree *tree, *tr;
355 proto_item *item, *ti;
356 const char *str;
357 va_list ap;
359 va_start(ap, fmt);
360 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
361 va_end(ap);
363 tree = proto_item_add_subtree(item, ett_CPropertyRestriction);
365 v->relop = tvb_get_letohl(tvb, offset);
366 str = val_to_str(v->relop, PR_VALS, "0x%04x");
367 proto_tree_add_text(tree, tvb, offset, 4, "relop: %s (0x%04x)",
368 str[0]=='\0' ? "" : str, v->relop);
369 proto_item_append_text(item, " Op: %s", str);
370 offset += 4;
372 ti = proto_tree_add_text(tree, tvb, offset, 0, "Property");
373 tr = proto_item_add_subtree(ti, ett_mswsp_property_restriction);
374 offset = parse_CFullPropSpec(tvb, offset, tr, pad_tree, &v->property);
375 proto_item_set_end(ti, tvb, offset);
377 offset = parse_CBaseStorageVariant(tvb, offset, tree, pad_tree, &v->prval, "prval");
379 offset = parse_padding(tvb, offset, 4, pad_tree, "padding_lcid");
381 v->lcid = tvb_get_letohl(tvb, offset);
382 proto_tree_add_text(tree, tvb, offset, 4, "lcid: 0x%08x", v->lcid);
383 offset += 4;
385 proto_item_set_end(item, tvb, offset);
387 return offset;
390 static int parse_CCoercionRestriction(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
391 proto_tree *pad_tree, struct CCoercionRestriction *v,
392 const char *fmt, ...)
394 proto_tree *tree;
395 proto_item *item;
396 va_list ap;
398 va_start(ap, fmt);
399 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
400 va_end(ap);
402 tree = proto_item_add_subtree(item, ett_CCoercionRestriction);
404 v->value = tvb_get_letohl(tvb, offset);
405 proto_tree_add_text(tree, tvb, offset, 4, "value: %g", (double)v->value);
406 offset += 4;
408 offset = parse_CRestriction(tvb, offset, tree, pad_tree, &v->child, "child");
410 proto_item_set_end(item, tvb, offset);
411 return offset;
414 static int parse_CContentRestriction(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
415 proto_tree *pad_tree, struct CContentRestriction *v,
416 const char *fmt, ...)
418 proto_tree *tree;
419 proto_item *item;
420 va_list ap;
421 guint32 cc;
422 const char *str;
425 va_start(ap, fmt);
426 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
427 va_end(ap);
429 tree = proto_item_add_subtree(item, ett_CContentRestriction);
431 offset = parse_CFullPropSpec(tvb, offset, tree, pad_tree, &v->property);
433 offset = parse_padding(tvb, offset, 4, pad_tree, "Padding1");
435 cc = tvb_get_letohl(tvb, offset);
436 proto_tree_add_text(tree, tvb, offset, 4, "cc: %u", cc);
437 offset += 4;
439 // str = tvb_get_ephemeral_string_enc(tvb, offset, 2*cc, ENC_UTF_16);
440 str = tvb_get_unicode_string(tvb, offset, 2*cc, ENC_LITTLE_ENDIAN);
441 v->phrase = se_strdup(str);
442 proto_tree_add_text(tree, tvb, offset, 2*cc, "phrase: %s", str);
443 offset += 2*cc;
445 offset = parse_padding(tvb, offset, 4, pad_tree, "Padding2");
447 v->lcid = tvb_get_letohl(tvb, offset);
448 proto_tree_add_text(tree, tvb, offset, 4, "lcid: 0x%08x", v->lcid);
449 offset += 4;
451 v->method = tvb_get_letohl(tvb, offset);
452 proto_tree_add_text(tree, tvb, offset, 4, "method: 0x%08x", v->method);
453 offset += 4;
455 proto_item_set_end(item, tvb, offset);
456 return offset;
460 static int parse_CReuseWhere(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
461 proto_tree *pad_tree _U_, struct CReuseWhere *v,
462 const char *fmt, ...)
464 proto_item *item;
465 va_list ap;
468 va_start(ap, fmt);
469 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
470 va_end(ap);
472 v->whereId = tvb_get_letohl(tvb, offset);
473 offset += 4;
475 proto_item_append_text(item, "Id: %u", v->whereId);
477 proto_item_set_end(item, tvb, offset);
478 return offset;
481 static value_string RT_VALS[] = {
482 {RTNone, "RTNone"},
483 {RTAnd, "RTAnd"},
484 {RTOr, "RTOr"},
485 {RTNot, "RTNot"},
486 {RTContent, "RTContent"},
487 {RTProperty, "RTProperty"},
488 {RTProximity, "RTProximity"},
489 {RTVector, ""},
490 {RTNatLanguage, "RTNatLanguage"},
491 {RTScope, "RTScope"},
492 {RTCoerce_Add, "RTCoerce_Add"},
493 {RTCoerce_Multiply, "RTCoerce_Multiply"},
494 {RTCoerce_Absolute, "RTCoerce_Absolute"},
495 {RTProb, "RTProb"},
496 {RTFeedback, "RTFeedback"},
497 {RTReldoc, "RTReldoc"},
498 {RTReuseWhere, "RTReuseWhere"},
499 {RTInternalProp, "RTInternalProp"},
500 {RTPhrase, "RTInternalProp"},
503 static int parse_CRestriction(tvbuff_t *tvb, int offset, proto_tree *parent_tree, proto_tree *pad_tree,
504 struct CRestriction *v, const char *fmt, ...)
506 proto_tree *tree;
507 proto_item *item, *ti;
508 const char *str;
509 va_list ap;
511 va_start(ap, fmt);
512 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
513 va_end(ap);
515 tree = proto_item_add_subtree(item, ett_CRestriction);
518 v->ulType = tvb_get_letohl(tvb, offset);
519 str = val_to_str(v->ulType, RT_VALS, "0x%.8x");
520 ti = proto_tree_add_text(tree, tvb, offset, 4, "ulType: %s (0x%.8x)",
521 str[0] == '0' ? "" : str, v->ulType);
522 proto_item_append_text(item, " Type: %s", str);
523 offset += 4;
525 v->Weight = tvb_get_letohl(tvb, offset);
526 ti = proto_tree_add_text(tree, tvb, offset, 4, "Weight: %u", v->ulType);
527 offset += 4;
529 switch(v->ulType) {
530 case RTNone:
531 break;
532 case RTAnd:
533 case RTOr:
534 case RTProximity:
535 case RTPhrase:
537 v->u.RTAnd = ep_alloc(sizeof(struct CNodeRestriction)); //XXX
538 offset = parse_CNodeRestriction(tvb, offset, tree, pad_tree, v->u.RTAnd, "CNodeRestriction");
539 break;
541 case RTNot:
543 v->u.RTNot = ep_alloc(sizeof(struct CRestriction)); //XXX
544 offset = parse_CRestriction(tvb, offset, tree, pad_tree,
545 v->u.RTNot, "CRestriction");
546 break;
548 case RTProperty:
550 v->u.RTProperty = ep_alloc(sizeof(struct CPropertyRestriction)); //XXX
551 offset = parse_CPropertyRestriction(tvb, offset, tree, pad_tree,
552 v->u.RTProperty, "CPropertyRestriction");
553 break;
555 case RTCoerce_Add:
556 case RTCoerce_Multiply:
557 case RTCoerce_Absolute:
559 v->u.RTCoerce_Add = ep_alloc(sizeof(struct CCoercionRestriction)); //XXX
560 offset = parse_CCoercionRestriction(tvb, offset, tree, pad_tree,
561 v->u.RTCoerce_Add, "CCoercionRestriction");
562 break;
564 case RTContent: {
565 v->u.RTContent = ep_alloc(sizeof(struct CContentRestriction)); //XXX
566 offset = parse_CContentRestriction(tvb, offset, tree, pad_tree,
567 v->u.RTContent, "CContentRestriction");
568 break;
570 case RTReuseWhere: {
571 v->u.RTReuseWhere = ep_alloc(sizeof(struct CReuseWhere)); //XXX
572 offset = parse_CReuseWhere(tvb, offset, tree, pad_tree,
573 v->u.RTReuseWhere, "CReuseWhere");
574 break;
576 default:
577 fprintf(stderr, "CRestriciont 0x%08x not Supported\n", v->ulType);
578 proto_item_append_text(item, " Not supported!");
581 proto_item_set_end(item, tvb, offset);
582 return offset;
585 static int parse_CNodeRestriction(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
586 proto_tree *pad_tree, struct CNodeRestriction *v,
587 const char *fmt, ...)
589 proto_tree *tree;
590 proto_item *item, *ti;
591 unsigned i;
592 va_list ap;
594 va_start(ap, fmt);
595 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
596 va_end(ap);
597 tree = proto_item_add_subtree(item, ett_CNodeRestriction);
599 v->cNode = tvb_get_letohl(tvb, offset);
600 ti = proto_tree_add_text(tree, tvb, offset, 4, "cNode: %u", v->cNode);
601 offset += 4;
602 for (i=0; i<v->cNode; i++) {
603 struct CRestriction r;
604 ZERO_STRUCT(r);
605 offset = parse_CRestriction(tvb, offset, tree, pad_tree, &r, "paNode[%u]", i);
607 offset = parse_padding(tvb, offset, 4, pad_tree, "paNode[%u]", i); /*at begin or end of loop ????*/
610 proto_item_set_end(item, tvb, offset);
611 return offset;
615 /*****************************************************************************************/
617 static int vvalue_tvb_get0(tvbuff_t *tvb _U_, int offset _U_, void *val _U_)
619 return 0;
622 static int vvalue_tvb_get1(tvbuff_t *tvb, int offset, void *val)
624 guint8 *ui1 = (guint8*)val;
625 *ui1 = tvb_get_guint8(tvb, offset);
626 return 1;
629 static int vvalue_tvb_get2(tvbuff_t *tvb , int offset, void *val)
631 guint16 *ui2 = (guint16*)val;
632 *ui2 = tvb_get_letohs(tvb, offset);
633 return 2;
636 static int vvalue_tvb_get4(tvbuff_t *tvb , int offset, void *val)
638 guint32 *ui4 = (guint32*)val;
639 *ui4 = tvb_get_letohl(tvb, offset);
640 return 4;
643 static int vvalue_tvb_get8(tvbuff_t *tvb , int offset, void *val)
645 guint64 *ui8 = (guint64*)val;
646 *ui8 = tvb_get_letoh64(tvb, offset);
647 return 8;
650 static int vvalue_tvb_blob(tvbuff_t *tvb , int offset, void *val)
652 struct data_blob *blob = (struct data_blob*)val;
653 guint32 len = tvb_get_letohl(tvb, offset);
654 const guint8 *data = tvb_get_ptr(tvb, offset + 4, len);
656 blob->size = len;
657 blob->data = se_memdup(data, len);
659 return 4 + len;
662 static int vvalue_tvb_bstr(tvbuff_t *tvb , int offset, void *val)
664 struct data_str *str = (struct data_str*)val;
665 guint32 len = tvb_get_letohl(tvb, offset);
666 const void *ptr = tvb_get_ptr(tvb, offset + 4, len);
668 //XXX this might be UTF-16
669 str->len = len;
670 str->str = se_strndup(ptr, len);
671 return 4 + len;
674 static int vvalue_tvb_lpstr(tvbuff_t *tvb , int offset, void *val)
676 struct data_str *str = (struct data_str*)val;
677 gint len;
679 str->len = tvb_get_letohl(tvb, offset);
680 str->str = tvb_get_seasonal_stringz(tvb, offset + 4, &len);
681 /* XXX test str->len == len */
682 return 4 + len;
685 static int vvalue_tvb_lpwstr(tvbuff_t *tvb , int offset, void *val)
687 struct data_str *str = (struct data_str*)val;
688 gint len;
689 gchar *ptr;
691 str->len = tvb_get_letohl(tvb, offset);
693 ptr = tvb_get_ephemeral_unicode_stringz(tvb, offset + 4, &len, ENC_LITTLE_ENDIAN);
694 str->str = se_strdup (ptr);
696 return 4 + len;
699 static int vvalue_tvb_vector_internal(tvbuff_t *tvb , int offset, struct vt_vector *val, struct vtype *type, int num)
701 const int offset_in = offset;
702 const gboolean varsize = (type->size == -1);
703 const int elsize = varsize ? (int)sizeof(struct data_blob) : type->size;
704 guint8 *data = se_alloc(elsize * num);
705 int len, i;
707 val->len = num;
708 val->u.vt_ui1 = data;
709 DISSECTOR_ASSERT((void*)&val->u == ((void*)&val->u.vt_ui1));
711 for (i=0; i<num; i++) {
712 len = type->tvb_get(tvb, offset, data);
713 data += elsize;
714 offset += len;
715 if (varsize && (offset % 4) ) { /* at begin or end of loop ??? */
716 int padding = 4 - (offset % 4);
717 offset += padding;
720 return offset - offset_in;
723 static int vvalue_tvb_vector(tvbuff_t *tvb , int offset, struct vt_vector *val, struct vtype *type)
725 const int num = tvb_get_letohl(tvb, offset);
726 return 4 + vvalue_tvb_vector_internal(tvb , offset+4, val, type, num);
729 static void vvalue_strbuf_append_null(emem_strbuf_t *strbuf _U_, void *ptr _U_)
732 static void vvalue_strbuf_append_i1(emem_strbuf_t *strbuf, void *ptr)
734 gint8 i1 = *(gint8*)ptr;
735 ep_strbuf_append_printf(strbuf, "%d", (int)i1);
738 static void vvalue_strbuf_append_i2(emem_strbuf_t *strbuf, void *ptr)
740 gint16 i2 = *(gint16*)ptr;
741 ep_strbuf_append_printf(strbuf, "%d", (int)i2);
744 static void vvalue_strbuf_append_i4(emem_strbuf_t *strbuf, void *ptr)
746 gint32 i4 = *(gint32*)ptr;
747 ep_strbuf_append_printf(strbuf, "%d", i4);
750 static void vvalue_strbuf_append_i8(emem_strbuf_t *strbuf, void *ptr)
752 gint64 i8 = *(gint64*)ptr;
753 ep_strbuf_append_printf(strbuf, "%ld", i8);
756 static void vvalue_strbuf_append_ui1(emem_strbuf_t *strbuf, void *ptr)
758 guint8 ui1 = *(guint8*)ptr;
759 ep_strbuf_append_printf(strbuf, "%u", (unsigned)ui1);
762 static void vvalue_strbuf_append_ui2(emem_strbuf_t *strbuf, void *ptr)
764 guint16 ui2 = *(guint16*)ptr;
765 ep_strbuf_append_printf(strbuf, "%u", (unsigned)ui2);
768 static void vvalue_strbuf_append_ui4(emem_strbuf_t *strbuf, void *ptr)
770 guint32 ui4 = *(guint32*)ptr;
771 ep_strbuf_append_printf(strbuf, "%d", ui4);
774 static void vvalue_strbuf_append_ui8(emem_strbuf_t *strbuf, void *ptr)
776 guint64 ui8 = *(guint64*)ptr;
777 ep_strbuf_append_printf(strbuf, "%lu", ui8);
780 static void vvalue_strbuf_append_r4(emem_strbuf_t *strbuf, void *ptr)
782 float r4 = *(float*)ptr;
783 ep_strbuf_append_printf(strbuf, "%g", (double)r4);
786 static void vvalue_strbuf_append_r8(emem_strbuf_t *strbuf, void *ptr)
788 double r8 = *(double*)ptr;
789 ep_strbuf_append_printf(strbuf, "%g", r8);
792 static void vvalue_strbuf_append_str(emem_strbuf_t *strbuf, void *ptr)
794 struct data_str *str = (struct data_str*)ptr;
795 ep_strbuf_append_printf(strbuf, "\"%s\"", str->str);
798 static void vvalue_strbuf_append_blob(emem_strbuf_t *strbuf, void *ptr)
800 struct data_blob *blob = (struct data_blob*)ptr;
801 ep_strbuf_append_printf(strbuf, "size: %d", (int)blob->size);
804 static void vvalue_strbuf_append_bool(emem_strbuf_t *strbuf, void *ptr)
806 guint16 val = *(guint*)ptr;
807 switch (val) {
808 case 0:
809 ep_strbuf_append(strbuf, "False");
810 break;
811 case 0xffff:
812 ep_strbuf_append(strbuf, "True");
813 break;
814 default:
815 ep_strbuf_append_printf(strbuf, "Invalid (0x%4x)", val);
819 static void vvalue_strbuf_append_vector(emem_strbuf_t *strbuf, struct vt_vector val, struct vtype *type)
821 const int elsize = (type->size == -1) ? (int)sizeof(struct data_blob) : type->size;
822 unsigned i;
823 guint8 *data = val.u.vt_ui1;
824 ep_strbuf_append_c(strbuf, '[');
825 for (i=0; i<val.len; i++) {
826 if (i>0) {
827 ep_strbuf_append_c(strbuf, ',');
829 type->strbuf_append(strbuf, data);
830 data += elsize;
832 ep_strbuf_append_c(strbuf, ']');
836 static struct vtype VT_TYPE[] = {
837 {VT_EMPTY, "VT_EMPTY", 0, vvalue_tvb_get0, vvalue_strbuf_append_null},
838 {VT_NULL, "VT_NULL", 0, vvalue_tvb_get0, vvalue_strbuf_append_null},
839 {VT_I2, "VT_I2", 2, vvalue_tvb_get2, vvalue_strbuf_append_i2},
840 {VT_I4, "VT_I4", 4, vvalue_tvb_get4, vvalue_strbuf_append_i4},
841 {VT_R4, "VT_R4", 4, vvalue_tvb_get4, vvalue_strbuf_append_r4},
842 {VT_R8, "VT_R8", 8, vvalue_tvb_get8, vvalue_strbuf_append_r8},
843 {VT_CY, "VT_CY", 8, vvalue_tvb_get8, vvalue_strbuf_append_i8},
844 {VT_DATE, "VT_DATE", 8, vvalue_tvb_get8, vvalue_strbuf_append_r8},
845 // {VT_BSTR, "VT_BSTR", -1, vvalue_tvb_bstr, vvalue_strbuf_append_str},
846 {VT_BSTR, "VT_BSTR", -1, vvalue_tvb_lpwstr, vvalue_strbuf_append_str},
847 {VT_ERROR, "VT_ERROR", 8, vvalue_tvb_get4, vvalue_strbuf_append_ui4},
848 {VT_BOOL, "VT_BOOL", 2, vvalue_tvb_get2, vvalue_strbuf_append_bool},
849 {VT_VARIANT, "VT_VARIANT", -1, NULL, NULL},
850 {VT_DECIMAL, "VT_DECIMAL", 16, NULL, NULL},
851 {VT_I1, "VT_I1", 1, vvalue_tvb_get1, vvalue_strbuf_append_i1},
852 {VT_UI1, "VT_UI1", 1, vvalue_tvb_get1, vvalue_strbuf_append_ui1},
853 {VT_UI2, "VT_UI2", 2, vvalue_tvb_get2, vvalue_strbuf_append_ui2},
854 {VT_UI4, "VT_UI4", 4, vvalue_tvb_get4, vvalue_strbuf_append_ui4},
855 {VT_I8, "VT_I8", 8, vvalue_tvb_get8, vvalue_strbuf_append_i8},
856 {VT_UI8, "VT_UI8", 8, vvalue_tvb_get8, vvalue_strbuf_append_ui8},
857 {VT_INT, "VT_INT", 4, vvalue_tvb_get4, vvalue_strbuf_append_i4},
858 {VT_UINT, "VT_UINT", 4, vvalue_tvb_get4, vvalue_strbuf_append_ui4},
859 {VT_LPSTR, "VT_LPSTR", -1, vvalue_tvb_lpstr, vvalue_strbuf_append_str},
860 {VT_LPWSTR, "VT_LPWSTR", -1, vvalue_tvb_lpwstr, vvalue_strbuf_append_str},
861 {VT_COMPRESSED_LPWSTR, "VT_COMPRESSED_LPWSTR", -1, NULL, vvalue_strbuf_append_str},
862 {VT_FILETIME, "VT_FILETIME", 8, vvalue_tvb_get8, vvalue_strbuf_append_i8},
863 {VT_BLOB, "VT_BLOB", -1, vvalue_tvb_blob, vvalue_strbuf_append_blob},
864 {VT_BLOB_OBJECT, "VT_BLOB_OBJECT", -1, vvalue_tvb_blob, vvalue_strbuf_append_blob},
865 {VT_CLSID, "VT_CLSID", 16, NULL, NULL},
868 static struct vtype *vType_get_type(enum vType t) {
869 unsigned i;
870 t &= 0xFF;
871 for (i=0; i<array_length(VT_TYPE); i++) {
872 if (t == VT_TYPE[i].tag) {
873 return &VT_TYPE[i];
876 return NULL;
879 static char *str_CBaseStorageVariant(struct CBaseStorageVariant *value, gboolean print_type)
882 emem_strbuf_t *strbuf = ep_strbuf_new(NULL);
883 if (value == NULL) {
884 return "<NULL>";
887 if (value->type == NULL) {
888 return "<??""?>";
891 if (print_type) {
892 ep_strbuf_append(strbuf, value->type->str);
894 if (value->vType & 0xFF00) {
895 ep_strbuf_append_printf(strbuf, "[%d]", value->vValue.vt_vector.len);
897 ep_strbuf_append(strbuf, ": ");
900 switch (value->vType & 0xFF00) {
901 case 0:
902 value->type->strbuf_append(strbuf, &value->vValue);
903 break;
904 case VT_ARRAY:
905 vvalue_strbuf_append_vector(strbuf, value->vValue.vt_array.vData, value->type);
906 break;
907 case VT_VECTOR:
908 vvalue_strbuf_append_vector(strbuf, value->vValue.vt_vector, value->type);
909 break;
910 default:
911 ep_strbuf_append(strbuf, "Invalid");
914 return strbuf->str;
917 static int parse_CBaseStorageVariant(tvbuff_t *tvb, int offset, proto_tree *parent_tree, proto_tree *pad_tree _U_,
918 struct CBaseStorageVariant *value, const char *text)
920 int i, len;
921 proto_item *ti, *ti_type, *ti_val;
922 proto_tree *tree, *tr;
923 enum vType baseType, highType;
925 ZERO_STRUCT(*value);
927 ti = proto_tree_add_text(parent_tree, tvb, offset, 0, "%s", text);
928 tree = proto_item_add_subtree(ti, ett_CBaseStorageVariant);
930 value->vType = tvb_get_letohs(tvb, offset);
931 value->type = vType_get_type(value->vType);
933 ti_type = proto_tree_add_text(tree, tvb, offset, 2, "vType: %s", value->type->str);
934 offset += 2;
936 value->vData1 = tvb_get_guint8(tvb, offset);
937 proto_tree_add_text(tree, tvb, offset, 1, "vData1: %d", value->vData1);
938 offset += 1;
940 value->vData2 = tvb_get_guint8(tvb, offset);
941 proto_tree_add_text(tree, tvb, offset, 1, "vData2: %d", value->vData2);
942 offset += 1;
944 baseType = value->vType & 0x00FF;
945 highType = value->vType & 0xFF00;
947 if (value->type == NULL) {
948 goto not_supported;
951 ti_val = proto_tree_add_text(tree, tvb, offset, 0, "vValue");
953 switch (highType) {
954 case VT_EMPTY:
955 len = value->type->tvb_get(tvb, offset, &value->vValue.vt_single);
956 offset += len;
957 break;
958 case VT_VECTOR:
959 proto_item_append_text(ti_type, "|VT_VECTOR");
960 tr = proto_item_add_subtree(ti_val, ett_CBaseStorageVariant_Vector);
962 len = vvalue_tvb_vector(tvb, offset, &value->vValue.vt_vector, value->type);
963 proto_tree_add_text(tr, tvb, offset, 4, "num: %d", value->vValue.vt_vector.len);
964 offset += len;
965 break;
966 case VT_ARRAY: {
967 guint16 cDims, fFeatures;
968 guint32 cbElements, cElements, lLbound;
969 int num = 1;
971 proto_item_append_text(ti_type, "|VT_ARRAY");
972 tr = proto_item_add_subtree(ti_val, ett_CBaseStorageVariant_Array);
974 cDims = tvb_get_letohs(tvb, offset);
975 proto_tree_add_text(tr, tvb, offset, 2, "cDims: %d", cDims);
976 offset += 2;
978 fFeatures = tvb_get_letohs(tvb, offset);
979 proto_tree_add_text(tr, tvb, offset, 2, "fFeaturess: %d", fFeatures);
980 offset += 2;
982 cbElements = tvb_get_letohl(tvb, offset);
983 proto_tree_add_text(tr, tvb, offset, 4, "cbElements: %d", cbElements);
984 offset += 4;
985 for (i=0; i<cDims; i++) {
986 cElements = tvb_get_letohl(tvb, offset);
987 lLbound = tvb_get_letohl(tvb, offset + 4);
988 proto_tree_add_text(tr, tvb, offset, 8, "Rgsabound[%d]: (%d:%d)", i, cElements, lLbound);
989 offset += 8;
990 num *= cElements;
993 len = vvalue_tvb_vector_internal(tvb , offset, &value->vValue.vt_array.vData, value->type, num);
994 offset += len;
995 break;
997 default:
998 proto_item_append_text(ti_type, "|0x%x", highType);
1000 proto_item_set_end(ti, tvb, offset);
1001 proto_item_set_end(ti_val, tvb, offset);
1003 proto_item_append_text(ti_val, " %s", str_CBaseStorageVariant(value, false));
1004 proto_item_append_text(ti, " %s", str_CBaseStorageVariant(value, true));
1006 goto done;
1008 not_supported:
1009 proto_item_append_text(ti, ": sorry, vType %02x not handled yet!", (unsigned)value->vType);
1010 done:
1011 return offset;
1014 enum {
1015 DBKIND_GUID_NAME = 0,
1016 DBKIND_GUID_PROPID = 1
1019 static int parse_CDbColId(tvbuff_t *tvb, int offset, proto_tree *parent_tree, proto_tree *pad_tree, const char *text)
1021 guint32 eKind, ulId;
1022 e_guid_t guid;
1023 static const char *KIND[] = {"DBKIND_GUID_NAME", "DBKIND_GUID_PROPID"};
1025 proto_item *tree_item = proto_tree_add_text(parent_tree, tvb, offset, 0, "%s", text);
1026 proto_tree *tree = proto_item_add_subtree(tree_item, ett_CDbColId);
1028 eKind = tvb_get_letohl(tvb, offset);
1029 proto_tree_add_text(tree, tvb, offset, 4, "eKind: %s (%u)", eKind < 2 ? KIND[eKind] : "???", eKind);
1030 offset += 4;
1032 offset = parse_padding(tvb, offset, 8, pad_tree, "paddingGuidAlign");
1034 offset = parse_guid(tvb, offset, tree, &guid, "GUID");
1036 ulId = tvb_get_letohl(tvb, offset);
1037 proto_tree_add_text(tree, tvb, offset, 4, "ulId: %d", ulId);
1038 offset += 4;
1040 if (eKind == DBKIND_GUID_NAME) {
1041 char *name;
1042 int len = ulId; //*2 ???
1043 name = tvb_get_unicode_string(tvb, offset, len, ENC_LITTLE_ENDIAN);
1044 proto_tree_add_text(tree, tvb, offset, len, "vString: \"%s\"", name);
1045 proto_item_append_text(tree_item, " \"%s\"", name);
1046 offset += len;
1047 } else if (eKind == DBKIND_GUID_PROPID) {
1048 proto_item_append_text(tree_item, " %08x", ulId);
1049 } else {
1050 proto_item_append_text(tree_item, "<INVALID>");
1053 proto_item_set_end(tree_item, tvb, offset);
1055 return offset;
1058 struct GuidPropertySet {
1059 e_guid_t guid;
1060 const char *def;
1061 const char *desc;
1062 const value_string *id_map;
1065 static int parse_CDbProp(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
1066 proto_tree *pad_tree, struct GuidPropertySet *propset,
1067 const char *fmt, ...)
1069 static const value_string EMPTY_VS[] = {{0, NULL}};
1070 const value_string *vs = (propset && propset->id_map) ? propset->id_map : EMPTY_VS;
1071 guint32 id, opt, status;
1072 struct CBaseStorageVariant value;
1073 proto_item *item;
1074 proto_tree *tree;
1075 const char *str;
1076 va_list ap;
1078 va_start(ap, fmt);
1079 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1080 va_end(ap);
1082 tree = proto_item_add_subtree(item, ett_CDbProp);
1084 id = tvb_get_letohl(tvb, offset);
1085 str = val_to_str(id, vs, "0x%08x");
1086 proto_tree_add_text(tree, tvb, offset, 4, "Id: %s (0x%08x)", str[0] == '0' ? "" : str, id);
1087 offset += 4;
1088 proto_item_append_text(item, " Id: %s", str);
1090 opt = tvb_get_letohl(tvb, offset);
1091 proto_tree_add_text(tree, tvb, offset, 4, "Options: %08x", opt);
1092 offset += 4;
1094 status = tvb_get_letohl(tvb, offset);
1095 proto_tree_add_text(tree, tvb, offset, 4, "Status: %08x", status);
1096 offset += 4;
1098 offset = parse_CDbColId(tvb, offset, tree, pad_tree, "colid");
1100 offset = parse_CBaseStorageVariant(tvb, offset, tree, pad_tree, &value, "vValue");
1102 str = str_CBaseStorageVariant(&value, true);
1103 proto_item_append_text(item, " %s", str);
1104 proto_item_set_end(item, tvb, offset);
1106 return offset;
1109 /* 2.2.1.31.1 */
1110 static const value_string DBPROPSET_FSCIFRMWRK_EXT_IDS[] = {
1111 {0x02, "DBPROP_CI_CATALOG_NAME"},
1112 {0x03, "DBPROP_CI_INCLUDE_SCOPES"},
1113 {0x04, "DBPROP_CI_SCOPE_FLAGS"},
1114 {0x07, "DBPROP_CI_QUERY_TYPE"},
1115 {0, NULL}
1118 static const value_string DBPROPSET_QUERYEXT_IDS[] = {
1119 {0x02, "DBPROP_USECONTENTINDEX"},
1120 {0x03, "DBPROP_DEFERNONINDEXEDTRIMMING"},
1121 {0x04, "DBPROP_USEEXTENDEDDBTYPES"},
1122 {0x05, "DBPROP_IGNORENOISEONLYCLAUSES"},
1123 {0x06, "DBPROP_GENERICOPTIONS_STRING"},
1124 {0x07, "DBPROP_FIRSTROWS"},
1125 {0x08, "DBPROP_DEFERCATALOGVERIFICATION"},
1126 {0x0a, "DBPROP_GENERATEPARSETREE"},
1127 {0x0c, "DBPROP_FREETEXTANYTERM"},
1128 {0x0d, "DBPROP_FREETEXTUSESTEMMING"},
1129 {0x0e, "DBPROP_IGNORESBRI"},
1130 {0x10, "DBPROP_ENABLEROWSETEVENTS"},
1131 {0, NULL}
1134 static const value_string DBPROPSET_CIFRMWRKCORE_EXT_IDS[] = {
1135 {0x02, "DBPROP_MACHINE"},
1136 {0x03, "DBPROP_CLIENT_CLSID"},
1137 {0, NULL}
1140 static const value_string DBPROPSET_MSIDXS_ROWSETEXT_IDS[] = {
1141 {0x02, "MSIDXSPROP_ROWSETQUERYSTATUS"},
1142 {0x03, "MSIDXSPROP_COMMAND_LOCALE_STRING"},
1143 {0x04, "MSIDXSPROP_QUERY_RESTRICTION"},
1144 {0x05, "MSIDXSPROP_PARSE_TREE"},
1145 {0x06, "MSIDXSPROP_MAX_RANK"},
1146 {0x07, "MSIDXSPROP_RESULTS_FOUND"},
1147 {0, NULL}
1150 static struct GuidPropertySet GuidPropertySet[] = {
1151 {{0xa9bd1526, 0x6a80, 0x11d0, {0x8c, 0x9d, 0x00, 0x20, 0xaf, 0x1d, 0x74, 0x0e}},
1152 "DBPROPSET_FSCIFRMWRK_EXT", "File system content index framework",
1153 DBPROPSET_FSCIFRMWRK_EXT_IDS},
1154 {{0xa7ac77ed, 0xf8d7, 0x11ce, {0xa7, 0x98, 0x00, 0x20, 0xf8, 0x00, 0x80, 0x25}},
1155 "DBPROPSET_QUERYEXT", "Query extension",
1156 DBPROPSET_QUERYEXT_IDS},
1157 {{0xafafaca5, 0xb5d1, 0x11d0, {0x8c, 0x62, 0x00, 0xc0, 0x4f, 0xc2, 0xdb, 0x8d}},
1158 "DBPROPSET_CIFRMWRKCORE_EXT", "Content index framework core",
1159 DBPROPSET_CIFRMWRKCORE_EXT_IDS},
1160 {{0xAA6EE6B0, 0xE828, 0x11D0, {0xB2, 0x3E, 0x00, 0xAA, 0x00, 0x47, 0xFC, 0x01}},
1161 "DBPROPSET_MSIDXS_ROWSETEXT", "???",
1162 DBPROPSET_MSIDXS_ROWSETEXT_IDS},
1165 static struct GuidPropertySet *GuidPropertySet_find_guid(const e_guid_t *guid)
1167 unsigned i;
1168 for (i=0; i<array_length(GuidPropertySet); i++) {
1169 if (guid_cmp(&GuidPropertySet[i].guid, guid) == 0) {
1170 return &GuidPropertySet[i];
1173 return NULL;
1176 static int parse_CDbPropSet(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
1177 proto_tree *pad_tree, const char *fmt, ...)
1179 int i, num;
1180 e_guid_t guid;
1181 struct GuidPropertySet *pset;
1182 proto_item *item;
1183 proto_tree *tree;
1184 va_list ap;
1186 va_start(ap, fmt);
1187 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1188 va_end(ap);
1190 tree = proto_item_add_subtree(item, ett_CDbPropSet);
1192 offset = parse_guid(tvb, offset, tree, &guid, "guidPropertySet");
1194 pset = GuidPropertySet_find_guid(&guid);
1196 if (pset) {
1197 proto_item_append_text(item, " \"%s\" (%s)", pset->desc, pset->def);
1198 } else {
1199 const char *guid_str = guid_to_str(&guid);
1200 proto_item_append_text(item, " {%s}", guid_str);
1203 offset = parse_padding(tvb, offset, 4, pad_tree, "guidPropertySet");
1205 num = tvb_get_letohl(tvb, offset);
1206 proto_tree_add_text(tree, tvb, offset, 4, "cProperties: %d", num);
1207 offset += 4;
1208 proto_item_append_text(item, " Num: %d", num);
1210 for (i = 0; i<num; i++) {
1211 offset = parse_padding(tvb, offset, 4, pad_tree, "aProp[%d]", i);
1212 offset = parse_CDbProp(tvb, offset, tree, pad_tree, pset, "aProp[%d]", i);
1215 proto_item_set_end(item, tvb, offset);
1216 return offset;
1219 static int parse_PropertySetArray(tvbuff_t *tvb, int offset, int size_offset,
1220 proto_tree *parent_tree, proto_tree *pad_tree,
1221 const char *fmt, ...)
1223 const int offset_in = offset;
1224 guint32 size, num;
1225 int i;
1226 proto_tree *tree;
1227 proto_item *item;
1228 va_list ap;
1230 va_start(ap, fmt);
1231 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1232 va_end(ap);
1234 tree = proto_item_add_subtree(item, ett_CDbPropSet_Array);
1236 size = tvb_get_letohl(tvb, size_offset);
1237 proto_tree_add_item(tree, hf_mswsp_msg_ConnectIn_Blob1, tvb,
1238 size_offset, 4, ENC_LITTLE_ENDIAN);
1240 num = tvb_get_letohl(tvb, offset);
1241 proto_tree_add_item(tree, hf_mswsp_msg_ConnectIn_PropSets_num, tvb,
1242 offset, 4, ENC_LITTLE_ENDIAN);
1243 offset += 4;
1245 for (i = 0; i < (int)num; i++) {
1246 offset = parse_CDbPropSet(tvb, offset, tree, pad_tree, "PropertySet[%d]", i);
1249 proto_item_set_end(item, tvb, offset);
1250 DISSECTOR_ASSERT(offset - offset_in == (int)size);
1251 return offset;
1254 int parse_CColumnSet(tvbuff_t *tvb, int offset, proto_tree *tree, const char *fmt, ...)
1256 guint32 count, v, i;
1257 proto_item *item;
1259 va_list ap;
1261 va_start(ap, fmt);
1262 item = proto_tree_add_text_valist(tree, tvb, offset, 0, fmt, ap);
1263 va_end(ap);
1265 count = tvb_get_letohl(tvb, offset);
1266 offset += 4;
1268 proto_item_append_text(item, " Count %u [", count);
1269 for (i=0; i<count; i++) {
1270 v = tvb_get_letohl(tvb, offset);
1271 offset += 4;
1272 if (i>0) {
1273 proto_item_append_text(item, ",%u", v);
1274 } else {
1275 proto_item_append_text(item, "%u", v);
1278 proto_item_append_text(item, "]");
1279 return offset;
1282 /* 2.2.1.23 RANGEBOUNDARY */
1283 int parse_RANGEBOUNDARY(tvbuff_t *tvb, int offset, proto_tree *parent_tree,
1284 proto_tree *pad_tree, const char *fmt, ...)
1286 guint32 ulType;
1287 guint8 labelPresent;
1288 proto_item *item;
1289 proto_tree *tree;
1290 struct CBaseStorageVariant prval;
1291 va_list ap;
1293 va_start(ap, fmt);
1294 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1295 tree = proto_item_add_subtree(item, ett_RANGEBOUNDARY);
1296 va_end(ap);
1298 ulType = tvb_get_letohl(tvb, offset);
1299 proto_tree_add_text(tree, tvb, offset, 4, "ulType 0x%08x", ulType);
1300 proto_item_append_text(item, ": Type 0x%08x", ulType);
1301 offset += 4;
1303 ZERO_STRUCT(prval);
1304 offset = parse_CBaseStorageVariant(tvb, offset, tree, pad_tree, &prval, "prVal");
1306 labelPresent = tvb_get_guint8(tvb, offset);
1307 proto_tree_add_text(tree, tvb, offset, 1, "labelPresent: %s", labelPresent ? "True" : "False");
1308 offset += 1;
1310 if (labelPresent) {
1311 guint32 ccLabel;
1312 const char *label;
1313 offset = parse_padding(tvb, offset, 4, pad_tree, "paddingLabelPresent");
1315 ccLabel = tvb_get_letohl(tvb, offset);
1316 proto_tree_add_text(tree, tvb, offset, 4, "ccLabel: %u", ccLabel);
1317 offset += 4;
1319 label = tvb_get_unicode_string(tvb, offset, 2*ccLabel, ENC_LITTLE_ENDIAN);
1320 proto_tree_add_text(tree, tvb, offset, 2*ccLabel, "Label: \"%s\"", label);
1321 proto_item_append_text(item, " Label: \"%s\"", label);
1322 offset += 2*ccLabel;
1325 proto_item_append_text(item, " Val: %s", str_CBaseStorageVariant(&prval, true));
1327 proto_item_set_end(item, tvb, offset);
1328 return offset;
1332 /* 2.2.1.22 CRangeCategSpec */
1333 int parse_CRangeCategSpec(tvbuff_t *tvb, int offset,
1334 proto_tree *parent_tree, proto_tree *pad_tree,
1335 const char *fmt, ...)
1337 proto_item *item;
1338 proto_tree *tree;
1339 va_list ap;
1340 unsigned i;
1341 guint32 lcid, cRange;
1343 va_start(ap, fmt);
1344 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1345 tree = proto_item_add_subtree(item, ett_CRangeCategSpec);
1346 va_end(ap);
1348 lcid = tvb_get_letohl(tvb, offset);
1349 proto_tree_add_text(tree, tvb, offset, 4, "Lcid 0x%08x", lcid);
1350 offset += 4;
1352 cRange = tvb_get_letohl(tvb, offset);
1353 proto_tree_add_text(tree, tvb, offset, 4, "cRange 0x%08x", cRange);
1354 offset += 4;
1356 for (i=0; i<cRange; i++) {
1357 offset = parse_RANGEBOUNDARY(tvb, offset, tree, pad_tree, "aRangeBegin[%u]", i);
1361 proto_item_set_end(item, tvb, offset);
1362 return offset;
1365 /* 2.2.1.21 CCategSpec */
1366 int parse_CCategSpec(tvbuff_t *tvb, int offset,
1367 proto_tree *parent_tree, proto_tree *pad_tree,
1368 const char *fmt, ...)
1370 proto_item *item;
1371 proto_tree *tree;
1373 va_list ap;
1374 guint32 type;
1376 va_start(ap, fmt);
1377 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1378 tree = proto_item_add_subtree(item, ett_CCategSpec);
1379 va_end(ap);
1381 type = tvb_get_letohl(tvb, offset);
1382 proto_tree_add_text(tree, tvb, offset, 4, "Type 0x%08x", type);
1383 proto_item_append_text(item, " Type %u", type);
1384 offset += 4;
1386 proto_tree_add_text(tree, tvb, offset, 16, "CSort");
1387 offset += 16;
1389 offset = parse_CRangeCategSpec(tvb, offset, tree, pad_tree, "CRangeCategSpec");
1391 proto_item_set_end(item, tvb, offset);
1392 return offset;
1395 /* 2.2.1.25 CAggregSpec */
1396 static int parse_CAggregSpec(tvbuff_t *tvb, int offset,
1397 proto_tree *parent_tree, proto_tree *pad_tree,
1398 const char *fmt, ...)
1400 proto_item *item;
1401 proto_tree *tree;
1402 va_list ap;
1403 guint8 type;
1404 guint32 ccAlias, idColumn, ulMaxNumToReturn, idRepresentative;
1405 const char *alias;
1407 va_start(ap, fmt);
1408 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1409 tree = proto_item_add_subtree(item, ett_CAggregSpec);
1410 va_end(ap);
1412 type = tvb_get_guint8(tvb, offset);
1413 proto_tree_add_text(tree, tvb, offset, 1, "type: %u", type);
1414 proto_item_append_text(item, "type: %u", type);
1415 offset += 1;
1417 offset = parse_padding(tvb, offset, 4, pad_tree, "padding");
1419 ccAlias = tvb_get_letohl(tvb, offset);
1420 proto_tree_add_text(tree, tvb, offset, 1, "ccAlias: %u", ccAlias);
1421 offset += 4;
1423 alias = tvb_get_unicode_string(tvb, offset, 2*ccAlias, ENC_LITTLE_ENDIAN);
1424 proto_tree_add_text(tree, tvb, offset, 2*ccAlias, "Alias: %s", alias);
1425 offset += 2*ccAlias;
1427 idColumn = tvb_get_letohl(tvb, offset);
1428 proto_tree_add_text(tree, tvb, offset, 1, "idColumn: %u", idColumn);
1429 offset += 4;
1430 /* Optional ???
1431 ulMaxNumToReturn, idRepresentative;
1434 proto_item_set_end(item, tvb, offset);
1435 return offset;
1438 /* 2.2.1.24 CAggregSet */
1439 static int parse_CAggregSet(tvbuff_t *tvb, int offset,
1440 proto_tree *parent_tree, proto_tree *pad_tree,
1441 const char *fmt, ...)
1443 guint32 cCount, i;
1444 proto_item *item;
1445 proto_tree *tree;
1447 va_list ap;
1449 va_start(ap, fmt);
1450 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1451 tree = proto_item_add_subtree(item, ett_CAggregSet);
1452 va_end(ap);
1454 cCount = tvb_get_letohl(tvb, offset);
1455 proto_tree_add_text(tree, tvb, offset, 4, "count: %u", cCount);
1456 offset += 4;
1458 for (i=0; i<cCount; i++) {
1459 /* 2.2.1.25 CAggregSpec */
1460 offset = parse_CAggregSpec(tvb, offset, tree, pad_tree, "AggregSpecs[%u]", i);
1463 proto_item_set_end(item, tvb, offset);
1464 return offset;
1467 /* 2.2.1.27 CAggregSortKey */
1468 static int parse_CAggregSortKey(tvbuff_t *tvb, int offset,
1469 proto_tree *parent_tree, proto_tree *pad_tree,
1470 const char *fmt, ...)
1472 guint32 order;
1473 proto_item *item;
1474 proto_tree *tree;
1476 va_list ap;
1478 va_start(ap, fmt);
1479 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1480 tree = proto_item_add_subtree(item, ett_CAggregSortKey);
1481 va_end(ap);
1483 order = tvb_get_letohl(tvb, offset);
1484 proto_tree_add_text(tree, tvb, offset, 4, "order: %u", order);
1485 offset += 4;
1487 offset = parse_CAggregSpec(tvb, offset, tree, pad_tree, "ColumnSpec");
1489 proto_item_set_end(item, tvb, offset);
1490 return offset;
1494 /* 2.2.1.26 CSortAggregSet */
1495 static int parse_CSortAggregSet(tvbuff_t *tvb, int offset,
1496 proto_tree *parent_tree, proto_tree *pad_tree,
1497 const char *fmt, ...)
1499 guint32 cCount, i;
1500 proto_item *item;
1501 proto_tree *tree;
1503 va_list ap;
1505 va_start(ap, fmt);
1506 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1507 tree = proto_item_add_subtree(item, ett_CSortAggregSet);
1508 va_end(ap);
1510 cCount = tvb_get_letohl(tvb, offset);
1511 proto_tree_add_text(tree, tvb, offset, 4, "count: %u", cCount);
1512 offset += 4;
1514 for (i=0; i<cCount; i++) {
1515 /* 2.2.1.27 CAggregSortKey */
1516 offset = parse_CAggregSortKey(tvb, offset, tree, pad_tree, "SortKeys[%u]", i);
1519 proto_item_set_end(item, tvb, offset);
1520 return offset;
1523 enum CInGroupSortAggregSet_type {
1524 GroupIdDefault = 0x00, /* The default for all ranges. */
1525 GroupIdMinValue = 0x01, /*The first range in the parent's group.*/
1526 GroupIdNull = 0x02, /*The last range in the parent's group.*/
1527 GroupIdValue = 0x03,
1530 /* 2.2.1.29 CInGroupSortAggregSet */
1531 static int parse_CInGroupSortAggregSet(tvbuff_t *tvb, int offset,
1532 proto_tree *parent_tree, proto_tree *pad_tree,
1533 const char *fmt, ...)
1535 proto_item *item;
1536 proto_tree *tree;
1537 va_list ap;
1538 enum CInGroupSortAggregSet_type type;
1540 va_start(ap, fmt);
1541 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1542 tree = proto_item_add_subtree(item, ett_CInGroupSortAggregSet);
1543 va_end(ap);
1545 type = tvb_get_guint8(tvb, offset);
1546 proto_tree_add_text(tree, tvb, offset, 1, "Type: 0x%02x", (unsigned)type);
1547 offset += 1;
1549 offset = parse_padding(tvb, offset, 4, pad_tree, "CInGroupSortAggregSet");
1551 if (type == GroupIdValue) {
1552 struct CBaseStorageVariant id;
1553 offset = parse_CBaseStorageVariant(tvb, offset, tree, pad_tree, &id, "inGroupId");
1556 offset = parse_CSortAggregSet(tvb, offset, tree, pad_tree, "SortAggregSet");
1558 proto_item_set_end(item, tvb, offset);
1559 return offset;
1563 /* 2.2.1.28 CInGroupSortAggregSets */
1564 static int parse_CInGroupSortAggregSets(tvbuff_t *tvb, int offset,
1565 proto_tree *parent_tree, proto_tree *pad_tree,
1566 const char *fmt, ...)
1568 guint32 cCount, i;
1569 proto_item *item;
1570 proto_tree *tree;
1572 va_list ap;
1574 va_start(ap, fmt);
1575 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1576 tree = proto_item_add_subtree(item, ett_CInGroupSortAggregSets);
1577 va_end(ap);
1579 cCount = tvb_get_letohl(tvb, offset);
1580 proto_tree_add_text(tree, tvb, offset, 4, "count: %u", cCount);
1581 offset += 4;
1583 for (i=0; i<cCount; i++) {
1584 /* 2.2.1.29 CInGroupSortAggregSet */
1585 offset = parse_CInGroupSortAggregSet(tvb, offset, tree, pad_tree, "SortSets[%u]", i);
1588 proto_item_set_end(item, tvb, offset);
1589 return offset;
1592 /* 2.2.1.20 CCategorizationSpec */
1593 int parse_CCategorizationSpec(tvbuff_t *tvb, int offset,
1594 proto_tree *parent_tree, proto_tree *pad_tree,
1595 const char *fmt, ...)
1597 guint32 cMaxResults;
1598 proto_item *item;
1599 proto_tree *tree;
1601 va_list ap;
1603 va_start(ap, fmt);
1604 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1605 tree = proto_item_add_subtree(item, ett_CCategorizationSpec);
1606 va_end(ap);
1608 /* 2.2.1.18 CColumnSet */
1609 offset = parse_CColumnSet(tvb, offset, tree, "csColumns");
1611 /* 2.2.1.21 CCategSpec */
1612 offset = parse_CCategSpec(tvb, offset, tree, pad_tree, "Spec");
1614 /* 2.2.1.24 CAggregSet */
1615 offset = parse_CAggregSet(tvb, offset, tree, pad_tree, "AggregSet");
1617 /* 2.2.1.26 CSortAggregSet */
1618 offset = parse_CSortAggregSet(tvb, offset, tree, pad_tree, "SortAggregSet");
1620 /* 2.2.1.28 CInGroupSortAggregSets */
1621 offset = parse_CInGroupSortAggregSets(tvb, offset, tree, pad_tree, "InGroupSortAggregSets");
1623 cMaxResults = tvb_get_letohl(tvb, offset);
1624 proto_tree_add_text(tree, tvb, offset, 4, "cMaxResults: %u", cMaxResults);
1625 offset += 4;
1627 proto_item_set_end(item, tvb, offset);
1628 return offset;
1631 int parse_CRowsetProperties(tvbuff_t *tvb, int offset,
1632 proto_tree *parent_tree, proto_tree *pad_tree _U_,
1633 const char *fmt, ...)
1636 proto_item *item;
1637 proto_tree *tree;
1639 va_list ap;
1641 va_start(ap, fmt);
1642 item = proto_tree_add_text_valist(parent_tree, tvb, offset, 0, fmt, ap);
1643 tree = proto_item_add_subtree(item, ett_CRowsetProperties);
1644 va_end(ap);
1646 proto_tree_add_text(tree, tvb, offset, 4, "uBooleanOptions");
1647 offset += 4;
1649 proto_tree_add_text(tree, tvb, offset, 4, "ulMaxOpenRows (ignored)");
1650 offset += 4;
1652 proto_tree_add_text(tree, tvb, offset, 4, "ulMemoryUsage (ignored)");
1653 offset += 4;
1655 proto_tree_add_text(tree, tvb, offset, 4, "cMaxResults");
1656 offset += 4;
1658 proto_tree_add_text(tree, tvb, offset, 4, "cCmdTimeout");
1659 offset += 4;
1661 proto_item_set_end(item, tvb, offset);
1662 return offset;
1667 /* Code to actually dissect the packets */
1669 static int dissect_CPMConnect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolean in)
1671 proto_item *ti;
1672 proto_tree *tree;
1673 gint offset = 16;
1674 guint len;
1675 guint32 version;
1677 ti = proto_tree_add_item(parent_tree, hf_mswsp_msg, tvb, offset, -1, ENC_NA);
1678 tree = proto_item_add_subtree(ti, ett_mswsp_msg);
1679 proto_item_set_text(ti, "CPMConnect%s", in ? "In" : "Out");
1680 col_append_str(pinfo->cinfo, COL_INFO, "Connect");
1682 version = tvb_get_letohl(tvb, offset);
1683 ti = proto_tree_add_item(tree, hf_mswsp_msg_Connect_Version, tvb,
1684 offset, 4, ENC_LITTLE_ENDIAN);
1685 if (version & 0xffff0000) {
1686 proto_item_append_text(ti, " 64 bit");
1688 switch (version & 0xffff) {
1689 case 0x102:
1690 proto_item_append_text(ti, " w2k8 or vista");
1691 break;
1692 case 0x109:
1693 proto_item_append_text(ti, " XP or w2k3, with Windows Search 4.0");
1694 break;
1695 case 0x700:
1696 proto_item_append_text(ti, " win7 or w2k8r2");
1697 break;
1699 offset += 4;
1701 if (in) {
1702 guint32 blob_size1_off, blob_size2_off;
1703 proto_tree *pad_tree;
1705 ti = proto_tree_add_text(tree, tvb, offset, 0, "Padding");
1706 pad_tree = proto_item_add_subtree(ti, ett_mswsp_pad);
1708 proto_tree_add_item(tree, hf_mswsp_msg_ConnectIn_ClientIsRemote, tvb,
1709 offset, 4, ENC_LITTLE_ENDIAN);
1710 offset += 4;
1712 /* _cbBlob1 */
1713 blob_size1_off = offset;
1714 offset += 4;
1716 offset = parse_padding(tvb, offset, 8, pad_tree, "_paddingcbBlob2");
1718 /* _cbBlob2 */
1719 blob_size2_off = offset;
1720 offset += 4;
1722 offset = parse_padding(tvb, offset, 16, pad_tree, "_padding");
1724 len = tvb_unicode_strsize(tvb, offset);
1725 ti = proto_tree_add_item(tree, hf_mswsp_msg_ConnectIn_MachineName, tvb,
1726 offset, len, ENC_UTF_16);
1727 /*This shouldnt be necessary, is this a bug or is there some GUI setting I've missed?*/
1728 proto_item_set_text(ti, "Remote machine: %s",
1729 tvb_get_unicode_string(tvb, offset, len, ENC_LITTLE_ENDIAN));
1730 offset += len;
1732 len = tvb_unicode_strsize(tvb, offset);
1733 ti = proto_tree_add_item(tree, hf_mswsp_msg_ConnectIn_UserName, tvb,
1734 offset, len, ENC_UTF_16);
1735 proto_item_set_text(ti, "User: %s", tvb_get_unicode_string(tvb, offset, len, ENC_LITTLE_ENDIAN));
1736 offset += len;
1738 offset = parse_padding(tvb, offset, 8, pad_tree, "_paddingcPropSets");
1740 offset = parse_PropertySetArray(tvb, offset, blob_size1_off, tree, pad_tree, "PropSets");
1742 offset = parse_padding(tvb, offset, 8, pad_tree, "paddingExtPropset");
1744 offset = parse_PropertySetArray(tvb, offset, blob_size2_off, tree, pad_tree, "ExtPropset");
1746 offset = parse_padding(tvb, offset, 8, pad_tree, "???");
1748 DISSECTOR_ASSERT(offset == (int)tvb_length(tvb));
1750 /* make "Padding" the last item */
1751 proto_tree_move_item(tree, ti, proto_tree_get_parent(pad_tree));
1752 } else {
1755 return tvb_length(tvb);
1758 static int dissect_CPMDisconnect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1760 col_append_str(pinfo->cinfo, COL_INFO, "Disconnect");
1761 return tvb_length(tvb);
1764 static int dissect_CPMCreateQuery(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, gboolean in)
1766 gint offset = 16;
1767 proto_item *ti;
1768 proto_tree *tree;
1770 ti = proto_tree_add_item(parent_tree, hf_mswsp_msg, tvb, offset, -1, ENC_NA);
1771 tree = proto_item_add_subtree(ti, ett_mswsp_msg);
1773 proto_item_set_text(ti, "CPMCreateQuery%s", in ? "In" : "Out");
1774 col_append_str(pinfo->cinfo, COL_INFO, "CreateQuery");
1776 if (in) {
1777 proto_item *ti = proto_tree_add_text(tree, tvb, offset, 0, "Padding");
1778 proto_tree *pad_tree = proto_item_add_subtree(ti, ett_mswsp_pad);
1779 guint8 CColumnSetPresent, CRestrictionPresent, CSortSetPresent, CCategorizationSetPresent;
1780 guint32 size = tvb_get_letohl(tvb, offset);
1781 proto_tree_add_text(tree, tvb, offset, 4, "size");
1782 proto_tree_add_text(tree, tvb, offset, size, "ALL");
1783 offset += 4;
1785 CColumnSetPresent = tvb_get_guint8(tvb, offset);
1786 proto_tree_add_text(tree, tvb, offset, 1, "CColumnSetPresent: %s", CColumnSetPresent ? "True" : "False");
1787 offset += 1;
1789 if (CColumnSetPresent) {
1790 offset = parse_padding(tvb, offset, 4, pad_tree, "paddingCColumnSetPresent");
1791 offset = parse_CColumnSet(tvb, offset, tree, "CColumnSet");
1794 CRestrictionPresent = tvb_get_guint8(tvb, offset);
1795 proto_tree_add_text(tree, tvb, offset, 1, "CRestrictionPresent: %s", CColumnSetPresent ? "True" : "False");
1796 offset += 1;
1797 if (CRestrictionPresent) {
1798 guint8 count, present;
1799 int i;
1800 count = tvb_get_guint8(tvb, offset);
1801 present = tvb_get_guint8(tvb, offset);
1802 ti = proto_tree_add_text(tree, tvb, offset, 0, "CRestrictionSet: count %d", count);
1803 offset += 2;
1804 if (present) {
1805 offset = parse_padding(tvb, offset, 4, pad_tree, "paddingCRestrictionPresent");
1807 for (i=0; i<count; i++) {
1808 struct CRestriction r;
1809 offset = parse_CRestriction(tvb, offset, tree, pad_tree, &r, "CRestrictionSet[%d]", i);
1812 proto_item_set_end(ti, tvb, offset);
1815 CSortSetPresent = tvb_get_guint8(tvb, offset);
1816 proto_tree_add_text(tree, tvb, offset, 1, "CSortSetPresent: %s", CSortSetPresent ? "True" : "False");
1817 offset += 1;
1818 if (CSortSetPresent) {
1819 guint32 count;
1820 offset = parse_padding(tvb, offset, 4, pad_tree, "paddingCSortSetPresent");
1821 /*2.2.1.43 CSortSet */
1822 /*2.2.1.10 CSort 16Bytes */
1823 count = tvb_get_letohl(tvb, offset);
1824 proto_tree_add_text(tree, tvb, offset, 4 + 16*count, "CSortSet: count %u", count);
1825 offset += (4 + 16*count);
1828 CCategorizationSetPresent = tvb_get_guint8(tvb, offset);
1829 proto_tree_add_text(tree, tvb, offset, 1, "CCategorizationSetPresent: %s", CCategorizationSetPresent ? "True" : "False");
1830 offset += 1;
1832 if (CCategorizationSetPresent) {
1833 guint32 count, i;
1834 offset = parse_padding(tvb, offset, 4, pad_tree, "paddingCCategorizationSetPresent");
1835 /* 2.2.1.19 CCategorizationSet */
1836 count = tvb_get_letohl(tvb, offset);
1837 proto_tree_add_text(tree, tvb, offset, 4, "count: %u", count);
1838 offset += 4;
1839 for (i=0; i<count; i++) {
1840 offset = parse_CCategorizationSpec(tvb, offset, tree, pad_tree, "categories[%u]", i);
1844 offset = parse_CRowsetProperties(tvb, offset, tree, pad_tree, "RowSetProperties");
1847 return tvb_length(tvb);
1850 static int dissect_CPMFreeCursor(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1852 col_append_str(pinfo->cinfo, COL_INFO, "FreeCursor");
1853 return tvb_length(tvb);
1856 static int dissect_CPMGetRows(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1858 col_append_str(pinfo->cinfo, COL_INFO, "GetRows");
1859 return tvb_length(tvb);
1862 static int dissect_CPMRatioFinished(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1864 col_append_str(pinfo->cinfo, COL_INFO, "RatioFinished");
1865 return tvb_length(tvb);
1868 static int dissect_CPMCompareBmk(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1870 col_append_str(pinfo->cinfo, COL_INFO, "CompareBmk");
1871 return tvb_length(tvb);
1874 static int dissect_CPMGetApproximatePosition(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1876 col_append_str(pinfo->cinfo, COL_INFO, "GetApproximatePosition");
1877 return tvb_length(tvb);
1880 static int dissect_CPMSetBindings(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1882 col_append_str(pinfo->cinfo, COL_INFO, "SetBindings");
1883 return tvb_length(tvb);
1886 static int dissect_CPMGetNotify(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1888 col_append_str(pinfo->cinfo, COL_INFO, "GetNotify");
1889 return tvb_length(tvb);
1892 static int dissect_CPMSendNotifyOut(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1894 col_append_str(pinfo->cinfo, COL_INFO, "SendNotify");
1895 return tvb_length(tvb);
1898 static int dissect_CPMGetQueryStatus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1900 col_append_str(pinfo->cinfo, COL_INFO, "GetQueryStatus");
1901 return tvb_length(tvb);
1904 static int dissect_CPMCiState(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1906 col_append_str(pinfo->cinfo, COL_INFO, "CiState");
1907 return tvb_length(tvb);
1910 static int dissect_CPMFetchValue(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1912 col_append_str(pinfo->cinfo, COL_INFO, "FetchValue");
1913 return tvb_length(tvb);
1916 static int dissect_CPMGetQueryStatusEx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1918 col_append_str(pinfo->cinfo, COL_INFO, "GetQueryStatusEx");
1919 return tvb_length(tvb);
1922 static int dissect_CPMRestartPosition(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1924 col_append_str(pinfo->cinfo, COL_INFO, "RestartPosition");
1925 return tvb_length(tvb);
1928 static int dissect_CPMSetCatState(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1930 col_append_str(pinfo->cinfo, COL_INFO, "SetCatState");
1931 return tvb_length(tvb);
1934 static int dissect_CPMGetRowsetNotify(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1936 col_append_str(pinfo->cinfo, COL_INFO, "GetRowsetNotify");
1937 return tvb_length(tvb);
1940 static int dissect_CPMFindIndices(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1942 col_append_str(pinfo->cinfo, COL_INFO, "FindIndices");
1943 return tvb_length(tvb);
1946 static int dissect_CPMSetScopePrioritization(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1948 col_append_str(pinfo->cinfo, COL_INFO, "SetScopePrioritization");
1949 return tvb_length(tvb);
1952 static int dissect_CPMGetScopeStatistics(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree _U_, gboolean in _U_)
1954 col_append_str(pinfo->cinfo, COL_INFO, "GetScopeStatistics");
1955 return tvb_length(tvb);
1960 dissect_mswsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gboolean in)
1962 static const char *dbg_wait = NULL;
1963 static int wait_frame = -1;
1965 proto_tree *mswsp_tree = NULL;
1966 struct {
1967 guint32 msg;
1968 guint32 status;
1969 guint32 checksum;
1970 guint32 reserved;
1971 } hdr;
1972 int (*fn)(tvbuff_t*, packet_info*, proto_tree*, gboolean);
1974 if (tvb_length(tvb) < 16) {
1975 return 0;
1978 if (dbg_wait == NULL) {
1979 dbg_wait = getenv("DBG_FRAME");
1980 if (dbg_wait == NULL) {
1981 dbg_wait = "no";
1982 } else {
1983 wait_frame = atoi(dbg_wait);
1987 if ((int)pinfo->fd->num == wait_frame) {
1988 static volatile gboolean wait = 1;
1989 while(wait) {
1990 sleep(1);
1994 hdr.msg = tvb_get_letohl(tvb, 0);
1996 switch(hdr.msg) {
1997 case 0xC8:
1998 fn = dissect_CPMConnect;
1999 break;
2000 case 0xC9:
2001 fn = dissect_CPMDisconnect;
2002 break;
2003 case 0xCA:
2004 fn = dissect_CPMCreateQuery;
2005 break;
2006 case 0xCB:
2007 fn = dissect_CPMFreeCursor;
2008 break;
2009 case 0xCC:
2010 fn = dissect_CPMGetRows;
2011 break;
2012 case 0xCD:
2013 fn = dissect_CPMRatioFinished;
2014 break;
2015 case 0xCE:
2016 fn = dissect_CPMCompareBmk;
2017 break;
2018 case 0xCF:
2019 fn = dissect_CPMGetApproximatePosition;
2020 break;
2021 case 0xD0:
2022 fn = dissect_CPMSetBindings;
2023 break;
2024 case 0xD1:
2025 fn = dissect_CPMGetNotify;
2026 break;
2027 case 0xD2:
2028 fn = dissect_CPMSendNotifyOut;
2029 break;
2030 case 0xD7:
2031 fn = dissect_CPMGetQueryStatus;
2032 break;
2033 case 0xD9:
2034 fn = dissect_CPMCiState;
2035 break;
2036 case 0xE4:
2037 fn = dissect_CPMFetchValue;
2038 break;
2039 case 0xE7:
2040 fn = dissect_CPMGetQueryStatusEx;
2041 break;
2042 case 0xE8:
2043 fn = dissect_CPMRestartPosition;
2044 break;
2045 case 0xEC:
2046 fn = dissect_CPMSetCatState;
2047 break;
2048 case 0xF1:
2049 fn = dissect_CPMGetRowsetNotify;
2050 break;
2051 case 0xF2:
2052 fn = dissect_CPMFindIndices;
2053 break;
2054 case 0xF3:
2055 fn = dissect_CPMSetScopePrioritization;
2056 break;
2057 case 0xF4:
2058 fn = dissect_CPMGetScopeStatistics;
2059 break;
2060 default:
2061 return 0;
2064 hdr.status = tvb_get_letohl(tvb, 4);
2065 hdr.checksum = tvb_get_letohl(tvb, 8);
2067 col_set_str(pinfo->cinfo, COL_PROTOCOL, "MS-WSP");
2068 /* col_clear(pinfo->cinfo, COL_INFO); */
2070 col_set_str(pinfo->cinfo, COL_INFO, "WSP ");
2071 col_append_str(pinfo->cinfo, COL_INFO, in ? "Request: " : "Response: ");
2073 if (tree) {
2074 proto_tree *hdr_tree;
2075 proto_item *ti, *hti;
2077 ti = proto_tree_add_item(tree, proto_mswsp, tvb, 0, -1, ENC_NA);
2078 mswsp_tree = proto_item_add_subtree(ti, ett_mswsp);
2080 hti = proto_tree_add_item(mswsp_tree, hf_mswsp_hdr, tvb, 0, 16, ENC_NA);
2081 hdr_tree = proto_item_add_subtree(hti, ett_mswsp_hdr);
2083 proto_tree_add_item(hdr_tree, hf_mswsp_hdr_msg, tvb,
2084 0, 4, ENC_LITTLE_ENDIAN);
2085 proto_tree_add_item(hdr_tree, hf_mswsp_hdr_status,
2086 tvb, 4, 4, ENC_LITTLE_ENDIAN);
2087 proto_tree_add_item(hdr_tree, hf_mswsp_hdr_checksum,
2088 tvb, 8, 4, ENC_LITTLE_ENDIAN);
2089 proto_tree_add_item(hdr_tree, hf_mswsp_hdr_reserved, tvb,
2090 12, 4, ENC_LITTLE_ENDIAN);
2093 fn(tvb, pinfo, mswsp_tree, in);
2095 /* Return the amount of data this dissector was able to dissect */
2096 return tvb_length(tvb);
2100 /* Register the protocol with Wireshark */
2102 /* this format is require because a script is used to build the C function
2103 that calls all the protocol registration.
2106 void
2107 proto_register_mswsp(void)
2109 module_t *mswsp_module;
2111 /* Setup list of header fields See Section 1.6.1 for details*/
2112 static const value_string msg_ids[] = {
2113 {0x000000C8, "CPMConnect"}, /* In/Out */
2114 {0x000000C9, "CPMDisconnect"},
2115 {0x000000CA, "CPMCreateQuery"}, /* In/Out */
2116 {0x000000CB, "CPMFreeCursor"}, /* In/Out */
2117 {0x000000CC, "CPMGetRows"}, /* In/Out */
2118 {0x000000CD, "CPMRatioFinished"}, /* In/Out */
2119 {0x000000CE, "CPMCompareBmk"}, /* In/Out */
2120 {0x000000CF, "CPMGetApproximatePosition"}, /* In/Out */
2121 {0x000000D0, "CPMSetBindingsIn"},
2122 {0x000000D1, "CPMGetNotify"},
2123 {0x000000D2, "CPMSendNotifyOut"},
2124 {0x000000D7, "CPMGetQueryStatusIn"}, /* In/Out */
2125 {0x000000D9, "CPMCiStateInOut"},
2126 {0x000000E4, "CPMFetchValue"}, /* In/Out */
2127 {0x000000E7, "CPMGetQueryStatusEx"}, /* In/Out */
2128 {0x000000E8, "CPMRestartPositionIn"},
2129 {0x000000EC, "CPMSetCatStateIn"}, /* (not supported) */
2130 {0x000000F1, "CPMGetRowsetNotify"}, /* In/Out */
2131 {0x000000F2, "CPMFindIndices"}, /* In/Out */
2132 {0x000000F3, "CPMSetScopePrioritization"}, /* In/Out */
2133 {0x000000F4, "CPMGetScopeStatistics"}, /* In/Out */
2135 static hf_register_info hf[] = {
2136 { &hf_mswsp_hdr,
2137 { "Header", "mswsp.hdr",
2138 FT_NONE, BASE_NONE , NULL, 0,
2139 "Message header", HFILL }
2141 { &hf_mswsp_hdr_msg,
2142 { "Msg id", "mswsp.hdr.id",
2143 FT_UINT32, BASE_HEX , VALS(msg_ids), 0,
2144 "Message id", HFILL }
2146 { &hf_mswsp_hdr_status,
2147 { "Status", "mswsp.hdr.status",
2148 FT_UINT32, BASE_HEX , NULL, 0,
2149 "Status", HFILL }
2151 { &hf_mswsp_hdr_checksum,
2152 { "checksum", "mswsp.hdr.checksum",
2153 FT_UINT32, BASE_HEX , NULL, 0,
2154 "Checksum", HFILL }
2156 { &hf_mswsp_hdr_reserved,
2157 { "Reserved", "mswsp.hdr.reserved",
2158 FT_UINT32, BASE_HEX , NULL, 0,
2159 "Reserved", HFILL }
2161 { &hf_mswsp_msg,
2162 { "msg", "mswsp.msg",
2163 FT_NONE, BASE_NONE , NULL, 0,
2164 "Message", HFILL }
2166 { &hf_mswsp_msg_Connect_Version,
2167 { "Version", "mswsp.Connect.version",
2168 FT_UINT32, BASE_HEX , NULL, 0,
2169 "Version",HFILL }
2171 { &hf_mswsp_msg_ConnectIn_ClientIsRemote,
2172 { "Remote", "mswsp.ConnectIn.isRemote",
2173 FT_BOOLEAN, BASE_HEX , NULL, 0,
2174 "Client is remote",HFILL }
2176 { &hf_mswsp_msg_ConnectIn_Blob1,
2177 { "Size", "mswsp.ConnectIn.propset.size",
2178 FT_UINT32, BASE_DEC , NULL, 0,
2179 "Size of PropSet fields",HFILL }
2181 { &hf_mswsp_msg_ConnectIn_Blob2,
2182 { "Size", "mswsp.ConnectIn.extpropset.size",
2183 FT_UINT32, BASE_DEC , NULL, 0,
2184 "Size of ExtPropSet fields",HFILL }
2186 { &hf_mswsp_msg_ConnectIn_MachineName,
2187 { "Remote machine", "mswsp.ConnectIn.machine",
2188 FT_STRINGZ, BASE_NONE , NULL, 0,
2189 "Name of remote machine",HFILL }
2191 { &hf_mswsp_msg_ConnectIn_UserName,
2192 { "User", "mswsp.ConnectIn.user",
2193 FT_STRINGZ, BASE_NONE , NULL, 0,
2194 "Name of remote user",HFILL }
2196 { &hf_mswsp_msg_ConnectIn_PropSets_num,
2197 { "Num", "mswsp.ConnectIn.propset.num",
2198 FT_UINT32, BASE_DEC , NULL, 0,
2199 "Number of Property Sets", HFILL }
2201 { &hf_mswsp_msg_ConnectIn_ExtPropSets_num,
2202 { "Num", "mswsp.ConnectIn.extpropset.num",
2203 FT_UINT32, BASE_DEC , NULL, 0,
2204 "Number of extended Property Sets", HFILL }
2209 /* Setup protocol subtree array */
2210 static gint *ett[] = {
2211 &ett_mswsp,
2212 &ett_mswsp_hdr,
2213 &ett_mswsp_msg,
2214 &ett_mswsp_pad,
2215 &ett_mswsp_property_restriction,
2216 &ett_CRestrictionArray,
2217 &ett_CBaseStorageVariant,
2218 &ett_CBaseStorageVariant_Vector,
2219 &ett_CBaseStorageVariant_Array,
2220 &ett_CDbColId,
2221 &ett_GUID,
2222 &ett_CDbProp,
2223 &ett_CDbPropSet,
2224 &ett_CDbPropSet_Array,
2225 &ett_CRestriction,
2226 &ett_CNodeRestriction,
2227 &ett_CPropertyRestriction,
2228 &ett_CCoercionRestriction,
2229 &ett_CContentRestriction,
2230 &ett_RANGEBOUNDARY,
2231 &ett_CRangeCategSpec,
2232 &ett_CCategSpec,
2233 &ett_CAggregSpec,
2234 &ett_CAggregSet,
2235 &ett_CCategorizationSpec,
2236 &ett_CAggregSortKey,
2237 &ett_CSortAggregSet,
2238 &ett_CInGroupSortAggregSet,
2239 &ett_CInGroupSortAggregSets,
2240 &ett_CRowsetProperties,
2243 int i;
2245 /* Register the protocol name and description */
2246 proto_mswsp = proto_register_protocol("Windows Search Protocol",
2247 "MS-WSP", "mswsp");
2249 /* Required function calls to register the header fields and subtrees used */
2250 proto_register_field_array(proto_mswsp, hf, array_length(hf));
2251 proto_register_subtree_array(ett, array_length(ett));
2253 for (i=0; i<(int)array_length(GuidPropertySet); i++) {
2254 guids_add_guid(&GuidPropertySet[i].guid, GuidPropertySet[i].def);
2258 /* Register preferences module (See Section 2.6 for more on preferences) */
2259 /* (Registration of a prefs callback is not required if there are no */
2260 /* prefs-dependent registration functions (eg: a port pref). */
2261 /* See proto_reg_handoff below. */
2262 /* If a prefs callback is not needed, use NULL instead of */
2263 /* proto_reg_handoff_mswsp in the following). */
2264 mswsp_module = prefs_register_protocol(proto_mswsp,
2265 proto_reg_handoff_mswsp);
2267 /* Register preferences module under preferences subtree.
2268 Use this function instead of prefs_register_protocol if you want to group
2269 preferences of several protocols under one preferences subtree.
2270 Argument subtree identifies grouping tree node name, several subnodes can be
2271 specified using slash '/' (e.g. "OSI/X.500" - protocol preferences will be
2272 accessible under Protocols->OSI->X.500-><PROTOSHORTNAME> preferences node.
2274 /* mswsp_module = prefs_register_protocol_subtree(subtree, */
2275 /* proto_mswsp, proto_reg_handoff_mswsp); */
2277 /* Register a sample preference */
2278 prefs_register_bool_preference(mswsp_module, "show_hex",
2279 "Display numbers in Hex",
2280 "Enable to display numerical values in hexadecimal.",
2281 &gPREF_HEX);
2283 /* Register a sample port preference */
2284 prefs_register_uint_preference(mswsp_module, "tcp.port", "mswsp TCP Port",
2285 " mswsp TCP port if other than the default",
2286 10, &gPORT_PREF);
2289 static int dissect_mswsp_smb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
2290 smb_info_t *si = pinfo->private_data;
2291 gboolean in = si->request;
2293 fprintf(stderr, "dissect_mswsp_smb %d <> %d : op %02x %s %s type: %d\n",
2294 pinfo->fd->num, si->tid,
2295 si->cmd,
2296 pinfo->dcerpc_procedure_name ? pinfo->dcerpc_procedure_name : "<NULL>",
2297 in ? "Request" : "Response", si->tid);
2300 if (strcmp(pinfo->dcerpc_procedure_name, "File: MsFteWds") != 0) {
2301 return 0;
2304 return dissect_mswsp(tvb, pinfo, tree, in);
2308 static int dissect_mswsp_smb2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
2309 smb2_info_t *si = pinfo->private_data;
2310 gboolean in = !(si->flags & SMB2_FLAGS_RESPONSE);
2312 //si->tree->share_type == SMB2_SHARE_TYPE_PIPE
2313 //si->tree->connect_frame
2315 fprintf(stderr, "dissect_mswsp %d <> %d : op %02x %s %s type: %d extra_file: %s\n",
2316 pinfo->fd->num, si->tree ? (int)si->tree->connect_frame : -1,
2317 si->opcode,
2318 pinfo->dcerpc_procedure_name ? pinfo->dcerpc_procedure_name : "<NULL>",
2319 in ? "Request" : "Response", si->tree ? si->tree->share_type : -1,
2320 si->saved ? (si->saved->extra_info_type == SMB2_EI_FILENAME ? (char*)si->saved->extra_info : "<OTHER>") : "<NONE>"
2324 if (strcmp(pinfo->dcerpc_procedure_name, "File: MsFteWds") != 0) {
2325 return 0;
2328 return dissect_mswsp(tvb, pinfo, tree, in);
2333 /* If this dissector uses sub-dissector registration add a registration routine.
2334 This exact format is required because a script is used to find these
2335 routines and create the code that calls these routines.
2337 If this function is registered as a prefs callback (see prefs_register_protocol
2338 above) this function is also called by preferences whenever "Apply" is pressed;
2339 In that case, it should accommodate being called more than once.
2341 Simple form of proto_reg_handoff_mswsp which can be used if there are
2342 no prefs-dependent registration function calls.
2345 void
2346 proto_reg_handoff_mswsp(void)
2348 heur_dissector_add("smb_transact", dissect_mswsp_smb, proto_mswsp);
2349 heur_dissector_add("smb2_heur_subdissectors", dissect_mswsp_smb2, proto_mswsp);
2354 * Editor modelines - http://www.wireshark.org/tools/modelines.html
2356 * Local variables:
2357 * c-basic-offset: 4
2358 * tab-width: 8
2359 * indent-tabs-mode: nil
2360 * End:
2362 * vi: set shiftwidth=4 tabstop=8 expandtab:
2363 * :indentSize=4:tabSize=8:noTabs=true: