signature=1c79d58d04498553c591967102afe603,D-Bus: dbus-marshal-recursive.c Source File

1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */

2 /* dbus-marshal-recursive.c Marshalling routines for recursive types

3 *

4 * Copyright (C) 2004, 2005 Red Hat, Inc.

5 *

6 * Licensed under the Academic Free License version 2.1

7 *

8 * This program is free software; you can redistribute it and/or modify

9 * it under the terms of the GNU General Public License as published by

10 * the Free Software Foundation; either version 2 of the License, or

11 * (at your option) any later version.

12 *

13 * This program is distributed in the hope that it will be useful,

14 * but WITHOUT ANY WARRANTY; without even the implied warranty of

15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

16 * GNU General Public License for more details.

17 *

18 * You should have received a copy of the GNU General Public License

19 * along with this program; if not, write to the Free Software

20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

21 *

22 */

23

24 #include

25 #include "dbus-marshal-recursive.h"

26 #include "dbus-marshal-basic.h"

27 #include "dbus-signature.h"

28 #include "dbus-internals.h"

29

35 static dbus_bool_t _dbus_type_reader_greater_than (const DBusTypeReader *lhs,

37

38 static void _dbus_type_writer_set_enabled (DBusTypeWriter *writer,

39  dbus_bool_t enabled);

40 static dbus_bool_t _dbus_type_writer_write_reader_partial (DBusTypeWriter *writer,

42  const DBusTypeReader *start_after,

43  int start_after_new_pos,

44  int start_after_new_len,

45  DBusList **fixups);

46

#define RECURSIVE_MARSHAL_READ_TRACE 0

49

#define RECURSIVE_MARSHAL_WRITE_TRACE 0

52

53 static void

54 free_fixups (DBusList **fixups)

55 {

56  DBusList *link;

57

59  while (link != NULL)

60  {

61  DBusList *next;

62

64

67

68  link = next;

69  }

70

71  *fixups = NULL;

72 }

73

74 static void

75 apply_and_free_fixups (DBusList **fixups,

77 {

78  DBusList *link;

79

80 #if RECURSIVE_MARSHAL_WRITE_TRACE

81  if (*fixups)

82  _dbus_verbose (" %d FIXUPS to apply\n",

84 #endif

85

87  while (link != NULL)

88  {

89  DBusList *next;

90

92

93  if (reader)

94  {

96

97  f = link->data;

98

99 #if RECURSIVE_MARSHAL_WRITE_TRACE

100  _dbus_verbose (" applying FIXUP to reader %p at pos %d new_len = %d old len %d\n",

104  reader->byte_order, NULL));

105 #endif

106

109  f->new_len,

110  reader->byte_order);

111  }

112

115

116  link = next;

117  }

118

119  *fixups = NULL;

120 }

121

126 {

const char *name;

recurse) (DBusTypeReader *sub,

next) (DBusTypeReader *reader,

134  int current_type);

135 };

136

137 static int

138 element_type_get_alignment (const DBusString *str,

139  int pos)

140 {

142 }

143

144 static void

145 reader_init (DBusTypeReader *reader,

146  int byte_order,

147  const DBusString *type_str,

148  int type_pos,

149  const DBusString *value_str,

150  int value_pos)

151 {

152  _DBUS_ZERO (*reader);

153  reader->byte_order = byte_order;

154  reader->finished = FALSE;

155  reader->type_str = type_str;

156  reader->type_pos = type_pos;

157  reader->value_str = value_str;

158  reader->value_pos = value_pos;

159 }

160

161 static void

162 base_reader_recurse (DBusTypeReader *sub,

164 {

165  /* point subreader at the same place as parent */

166  reader_init (sub,

167  parent->byte_order,

168  parent->type_str,

169  parent->type_pos,

170  parent->value_str,

171  parent->value_pos);

172 }

173

174 static void

175 struct_or_dict_entry_types_only_reader_recurse (DBusTypeReader *sub,

177 {

178  base_reader_recurse (sub, parent);

179

180  _dbus_assert (_dbus_string_get_byte (sub->type_str,

182  _dbus_string_get_byte (sub->type_str,

184

185  sub->type_pos += 1;

186 }

187

188 static void

189 struct_or_dict_entry_reader_recurse (DBusTypeReader *sub,

191 {

192  struct_or_dict_entry_types_only_reader_recurse (sub, parent);

193

194  /* struct and dict entry have 8 byte alignment */

195  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);

196 }

197

198 static void

199 array_types_only_reader_recurse (DBusTypeReader *sub,

201 {

202  base_reader_recurse (sub, parent);

203

204  /* point type_pos at the array element type */

205  sub->type_pos += 1;

206

207  /* Init with values likely to crash things if misused */

208  sub->u.array.start_pos = _DBUS_INT_MAX;

210 }

211

#define ARRAY_READER_LEN_POS(reader) \

215 ((reader)->u.array.start_pos - ((int)(reader)->array_len_offset) - 4)

216

217 static int

218 array_reader_get_array_len (const DBusTypeReader *reader)

219 {

220  dbus_uint32_t array_len;

221  int len_pos;

222

223  len_pos = ARRAY_READER_LEN_POS (reader);

224

225  _dbus_assert (_DBUS_ALIGN_VALUE (len_pos, 4) == (unsigned) len_pos);

227  _dbus_string_get_const_udata_len (reader->value_str, len_pos, 4));

228

229 #if RECURSIVE_MARSHAL_READ_TRACE

230  _dbus_verbose (" reader %p len_pos %d array len %u len_offset %d\n",

231  reader, len_pos, array_len, reader->array_len_offset);

232 #endif

233

234  _dbus_assert (reader->u.array.start_pos - len_pos - 4 < 8);

235

236  return array_len;

237 }

238

239 static void

240 array_reader_recurse (DBusTypeReader *sub,

242 {

243  int alignment;

244  int len_pos;

245

246  array_types_only_reader_recurse (sub, parent);

247

248  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);

249

250  len_pos = sub->value_pos;

251

252  sub->value_pos += 4; /* for the length */

253

254  alignment = element_type_get_alignment (sub->type_str,

255  sub->type_pos);

256

257  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);

258

259  sub->u.array.start_pos = sub->value_pos;

260  _dbus_assert ((sub->u.array.start_pos - (len_pos + 4)) < 8); /* only 3 bits in array_len_offset */

261  sub->array_len_offset = sub->u.array.start_pos - (len_pos + 4);

262

263 #if RECURSIVE_MARSHAL_READ_TRACE

264  _dbus_verbose (" type reader %p array start = %d len_offset = %d array len = %d array element type = %s\n",

265  sub,

266  sub->u.array.start_pos,

268  array_reader_get_array_len (sub),

270  sub->type_pos)));

271 #endif

272 }

273

274 static void

275 variant_reader_recurse (DBusTypeReader *sub,

277 {

278  int sig_len;

279  int contained_alignment;

280

281  base_reader_recurse (sub, parent);

282

283  /* Variant is 1 byte sig length (without nul), signature with nul,

284 * padding to 8-boundary, then values

285 */

286

287  sig_len = _dbus_string_get_byte (sub->value_str, sub->value_pos);

288

290  sub->type_pos = sub->value_pos + 1;

291

292  sub->value_pos = sub->type_pos + sig_len + 1;

293

295  sub->type_pos));

296

297  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment);

298

299 #if RECURSIVE_MARSHAL_READ_TRACE

300  _dbus_verbose (" type reader %p variant containing '%s'\n",

301  sub,

302  _dbus_string_get_const_data_len (sub->type_str,

303  sub->type_pos, 0));

304 #endif

305 }

306

308 array_reader_check_finished (const DBusTypeReader *reader)

309 {

310  int end_pos;

311

312  /* return the array element type if elements remain, and

313 * TYPE_INVALID otherwise

314 */

315

316  end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);

317

318  _dbus_assert (reader->value_pos <= end_pos);

319  _dbus_assert (reader->value_pos >= reader->u.array.start_pos);

320

321  return reader->value_pos == end_pos;

322 }

323

324 static void

325 skip_one_complete_type (const DBusString *type_str,

326  int *type_pos)

327 {

328  _dbus_type_signature_next (_dbus_string_get_const_data (type_str),

329  type_pos);

330 }

331

340 void

342  int *type_pos)

343 {

344  const unsigned char *p;

345  const unsigned char *start;

346

347  _dbus_assert (type_str != NULL);

348  _dbus_assert (type_pos != NULL);

349

350  start = (const unsigned char *)type_str;

351  p = start + *type_pos;

352

355

356  while (*p == DBUS_TYPE_ARRAY)

357  ++p;

358

361

363  {

364  int depth;

365

366  depth = 1;

367

368  while (TRUE)

369  {

371

372  ++p;

373

375

377  depth += 1;

379  {

380  depth -= 1;

381  if (depth == 0)

382  {

383  ++p;

384  break;

385  }

386  }

387  }

388  }

390  {

391  int depth;

392

393  depth = 1;

394

395  while (TRUE)

396  {

398

399  ++p;

400

402

404  depth += 1;

406  {

407  depth -= 1;

408  if (depth == 0)

409  {

410  ++p;

411  break;

412  }

413  }

414  }

415  }

416  else

417  {

418  ++p;

419  }

420

421  *type_pos = (int) (p - start);

422 }

423

424 static int

425 find_len_of_complete_type (const DBusString *type_str,

426  int type_pos)

427 {

428  int end;

429

430  end = type_pos;

431

432  skip_one_complete_type (type_str, &end);

433

434  return end - type_pos;

435 }

436

437 static void

438 base_reader_next (DBusTypeReader *reader,

439  int current_type)

440 {

441  switch (current_type)

442  {

446  /* Scan forward over the entire container contents */

447  {

449

450  if (reader->klass->types_only && current_type == DBUS_TYPE_VARIANT)

451  ;

452  else

453  {

454  /* Recurse into the struct or variant */

456

457  /* Skip everything in this subreader */

459  {

460  /* nothing */;

461  }

462  }

463  if (!reader->klass->types_only)

464  reader->value_pos = sub.value_pos;

465

466  /* Now we are at the end of this container; for variants, the

467 * subreader's type_pos is totally inapplicable (it's in the

468 * value string) but we know that we increment by one past the

469 * DBUS_TYPE_VARIANT

470 */

471  if (current_type == DBUS_TYPE_VARIANT)

472  reader->type_pos += 1;

473  else

474  reader->type_pos = sub.type_pos;

475  }

476  break;

477

479  {

480  if (!reader->klass->types_only)

483  reader->type_pos + 1),

484  reader->byte_order,

485  &reader->value_pos);

486

487  skip_one_complete_type (reader->type_str, &reader->type_pos);

488  }

489  break;

490

491  default:

492  if (!reader->klass->types_only)

494  current_type, reader->byte_order,

495  &reader->value_pos);

496

497  reader->type_pos += 1;

498  break;

499  }

500 }

501

502 static void

503 struct_reader_next (DBusTypeReader *reader,

504  int current_type)

505 {

506  int t;

507

508  base_reader_next (reader, current_type);

509

510  /* for STRUCT containers we return FALSE at the end of the struct,

511 * for INVALID we return FALSE at the end of the signature.

512 * In both cases we arrange for get_current_type() to return INVALID

513 * which is defined to happen iff we're at the end (no more next())

514 */

515  t = _dbus_string_get_byte (reader->type_str, reader->type_pos);

517  {

518  reader->type_pos += 1;

519  reader->finished = TRUE;

520  }

521 }

522

523 static void

524 dict_entry_reader_next (DBusTypeReader *reader,

525  int current_type)

526 {

527  int t;

528

529  base_reader_next (reader, current_type);

530

531  /* for STRUCT containers we return FALSE at the end of the struct,

532 * for INVALID we return FALSE at the end of the signature.

533 * In both cases we arrange for get_current_type() to return INVALID

534 * which is defined to happen iff we're at the end (no more next())

535 */

536  t = _dbus_string_get_byte (reader->type_str, reader->type_pos);

538  {

539  reader->type_pos += 1;

540  reader->finished = TRUE;

541  }

542 }

543

544 static void

545 array_types_only_reader_next (DBusTypeReader *reader,

546  int current_type)

547 {

548  /* We have one "element" to be iterated over

549 * in each array, which is its element type.

550 * So the finished flag indicates whether we've

551 * iterated over it yet or not.

552 */

553  reader->finished = TRUE;

554 }

555

556 static void

557 array_reader_next (DBusTypeReader *reader,

558  int current_type)

559 {

560  /* Skip one array element */

561  int end_pos;

562

563  end_pos = reader->u.array.start_pos + array_reader_get_array_len (reader);

564

565 #if RECURSIVE_MARSHAL_READ_TRACE

566  _dbus_verbose (" reader %p array next START start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",

567  reader,

568  reader->u.array.start_pos,

569  end_pos, reader->value_pos,

571 #endif

572

573  _dbus_assert (reader->value_pos < end_pos);

574  _dbus_assert (reader->value_pos >= reader->u.array.start_pos);

575

577  reader->type_pos))

578  {

582  {

584

585  /* Recurse into the struct or variant */

587

588  /* Skip everything in this element */

590  {

591  /* nothing */;

592  }

593

594  /* Now we are at the end of this element */

595  reader->value_pos = sub.value_pos;

596  }

597  break;

598

600  {

603  reader->type_pos + 1),

604  reader->byte_order,

605  &reader->value_pos);

606  }

607  break;

608

609  default:

610  {

612  current_type, reader->byte_order,

613  &reader->value_pos);

614  }

615  break;

616  }

617

618 #if RECURSIVE_MARSHAL_READ_TRACE

619  _dbus_verbose (" reader %p array next END start_pos = %d end_pos = %d value_pos = %d current_type = %s\n",

620  reader,

621  reader->u.array.start_pos,

622  end_pos, reader->value_pos,

624 #endif

625

626  _dbus_assert (reader->value_pos <= end_pos);

627

628  if (reader->value_pos == end_pos)

629  {

630  skip_one_complete_type (reader->type_str,

631  &reader->type_pos);

632  }

633 }

634

635 static const DBusTypeReaderClass body_reader_class = {

636  "body", 0,

638  NULL, /* body is always toplevel, so doesn't get recursed into */

639  NULL,

640  base_reader_next

641 };

642

643 static const DBusTypeReaderClass body_types_only_reader_class = {

644  "body types", 1,

645  TRUE,

646  NULL, /* body is always toplevel, so doesn't get recursed into */

647  NULL,

648  base_reader_next

649 };

650

651 static const DBusTypeReaderClass struct_reader_class = {

652  "struct", 2,

654  struct_or_dict_entry_reader_recurse,

655  NULL,

656  struct_reader_next

657 };

658

659 static const DBusTypeReaderClass struct_types_only_reader_class = {

660  "struct types", 3,

661  TRUE,

662  struct_or_dict_entry_types_only_reader_recurse,

663  NULL,

664  struct_reader_next

665 };

666

667 static const DBusTypeReaderClass dict_entry_reader_class = {

668  "dict_entry", 4,

670  struct_or_dict_entry_reader_recurse,

671  NULL,

672  dict_entry_reader_next

673 };

674

675 static const DBusTypeReaderClass dict_entry_types_only_reader_class = {

676  "dict_entry types", 5,

677  TRUE,

678  struct_or_dict_entry_types_only_reader_recurse,

679  NULL,

680  dict_entry_reader_next

681 };

682

683 static const DBusTypeReaderClass array_reader_class = {

684  "array", 6,

686  array_reader_recurse,

687  array_reader_check_finished,

688  array_reader_next

689 };

690

691 static const DBusTypeReaderClass array_types_only_reader_class = {

692  "array types", 7,

693  TRUE,

694  array_types_only_reader_recurse,

695  NULL,

696  array_types_only_reader_next

697 };

698

699 static const DBusTypeReaderClass variant_reader_class = {

700  "variant", 8,

702  variant_reader_recurse,

703  NULL,

704  base_reader_next

705 };

706

707 #ifndef DBUS_DISABLE_ASSERT

708 static const DBusTypeReaderClass * const

709 all_reader_classes[] = {

710  &body_reader_class,

711  &body_types_only_reader_class,

712  &struct_reader_class,

713  &struct_types_only_reader_class,

714  &dict_entry_reader_class,

715  &dict_entry_types_only_reader_class,

716  &array_reader_class,

717  &array_types_only_reader_class,

718  &variant_reader_class

719 };

720 #endif

721

732 void

734  int byte_order,

735  const DBusString *type_str,

736  int type_pos,

737  const DBusString *value_str,

738  int value_pos)

739 {

740  reader_init (reader, byte_order, type_str, type_pos,

741  value_str, value_pos);

742

743  reader->klass = &body_reader_class;

744

745 #if RECURSIVE_MARSHAL_READ_TRACE

746  _dbus_verbose (" type reader %p init type_pos = %d value_pos = %d remaining sig '%s'\n",

747  reader, reader->type_pos, reader->value_pos,

748  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));

749 #endif

750 }

751

760 void

762  const DBusString *type_str,

763  int type_pos)

764 {

765  reader_init (reader, DBUS_COMPILER_BYTE_ORDER /* irrelevant */,

766  type_str, type_pos, NULL, _DBUS_INT_MAX /* crashes if we screw up */);

767

768  reader->klass = &body_types_only_reader_class;

769

770 #if RECURSIVE_MARSHAL_READ_TRACE

771  _dbus_verbose (" type reader %p init types only type_pos = %d remaining sig '%s'\n",

772  reader, reader->type_pos,

773  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));

774 #endif

775 }

776

785 int

787 {

788  int t;

789

790  if (reader->finished ||

792  (* reader->klass->check_finished) (reader)))

794  else

796  reader->type_pos);

797

802

803 #if 0

804  _dbus_verbose (" type reader %p current type_pos = %d type = %s\n",

805  reader, reader->type_pos,

807 #endif

808

809  return t;

810 }

811

820 int

822 {

823  int element_type;

824

826

828  reader->type_pos + 1);

829

830  return element_type;

831 }

832

837 int

839 {

840  return reader->value_pos;

841 }

842

852 void

854  const unsigned char **value_location)

855 {

857

858  *value_location = _dbus_string_get_const_udata_len (reader->value_str,

859  reader->value_pos,

860  0);

861 }

862

869 void

871  void *value)

872 {

873  int t;

874

876

878

880  reader->value_pos,

881  t, value,

882  reader->byte_order,

883  NULL);

884

885

886 #if RECURSIVE_MARSHAL_READ_TRACE

887  _dbus_verbose (" type reader %p read basic type_pos = %d value_pos = %d remaining sig '%s'\n",

888  reader, reader->type_pos, reader->value_pos,

889  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));

890 #endif

891 }

892

899 int

901 {

903  _dbus_assert (reader->klass == &array_reader_class);

904

905  return array_reader_get_array_len (reader);

906 }

907

923 void

925  const void **value,

926  int *n_elements)

927 {

928  int element_type;

929  int end_pos;

930  int remaining_len;

931  int alignment;

932  int total_len;

933

935  _dbus_assert (reader->klass == &array_reader_class);

936

938  reader->type_pos);

939

940  _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */

942

943  alignment = _dbus_type_get_alignment (element_type);

944

945  _dbus_assert (reader->value_pos >= reader->u.array.start_pos);

946

947  total_len = array_reader_get_array_len (reader);

948  end_pos = reader->u.array.start_pos + total_len;

949  remaining_len = end_pos - reader->value_pos;

950

951 #if RECURSIVE_MARSHAL_READ_TRACE

952  _dbus_verbose ("end_pos %d total_len %d remaining_len %d value_pos %d\n",

953  end_pos, total_len, remaining_len, reader->value_pos);

954 #endif

955

956  _dbus_assert (remaining_len <= total_len);

957

958  if (remaining_len == 0)

959  *value = NULL;

960  else

961  *value = _dbus_string_get_const_data_len (reader->value_str,

962  reader->value_pos,

963  remaining_len);

964

965  *n_elements = remaining_len / alignment;

966  _dbus_assert ((remaining_len % alignment) == 0);

967

968 #if RECURSIVE_MARSHAL_READ_TRACE

969  _dbus_verbose (" type reader %p read fixed array type_pos = %d value_pos = %d remaining sig '%s'\n",

970  reader, reader->type_pos, reader->value_pos,

971  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0));

972 #endif

973 }

974

987 void

990 {

991  int t;

993

995

996  switch (t)

997  {

999  if (reader->klass->types_only)

1000  klass = &struct_types_only_reader_class;

1001  else

1002  klass = &struct_reader_class;

1003  break;

1005  if (reader->klass->types_only)

1006  klass = &dict_entry_types_only_reader_class;

1007  else

1008  klass = &dict_entry_reader_class;

1009  break;

1011  if (reader->klass->types_only)

1012  klass = &array_types_only_reader_class;

1013  else

1014  klass = &array_reader_class;

1015  break;

1017  if (reader->klass->types_only)

1018  _dbus_assert_not_reached ("can't recurse into variant typecode");

1019  else

1020  klass = &variant_reader_class;

1021  break;

1022  default:

1023  _dbus_verbose ("recursing into type %s\n", _dbus_type_to_string (t));

1024 #ifndef DBUS_DISABLE_CHECKS

1026  _dbus_warn_check_failed ("You can't recurse into an empty array or off the end of a message body");

1027 #endif/* DBUS_DISABLE_CHECKS */

1028

1029  _dbus_assert_not_reached ("don't yet handle recursing into this type");

1030  }

1031

1033  _dbus_assert (klass == all_reader_classes[klass->id]);

1034

1035  (* klass->recurse) (sub, reader);

1036  sub->klass = klass;

1037

1038 #if RECURSIVE_MARSHAL_READ_TRACE

1039  _dbus_verbose (" type reader %p RECURSED type_pos = %d value_pos = %d remaining sig '%s'\n",

1040  sub, sub->type_pos, sub->value_pos,

1041  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0));

1042 #endif

1043 }

1044

1055 {

1056  int t;

1057

1059

1060 #if RECURSIVE_MARSHAL_READ_TRACE

1061  _dbus_verbose (" type reader %p START next() { type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",

1062  reader, reader->type_pos, reader->value_pos,

1063  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),

1065 #endif

1066

1068  return FALSE;

1069

1070  (* reader->klass->next) (reader, t);

1071

1072 #if RECURSIVE_MARSHAL_READ_TRACE

1073  _dbus_verbose (" type reader %p END next() type_pos = %d value_pos = %d remaining sig '%s' current_type = %s\n",

1074  reader, reader->type_pos, reader->value_pos,

1075  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),

1077 #endif

1078

1080 }

1081

1095 {

1096  /* Not efficient but works for now. */

1098

1099  copy = *reader;

1101 }

1102

1124 void

1126  const DBusString **str_p,

1127  int *start_p,

1128  int *len_p)

1129 {

1130  *str_p = reader->type_str;

1131  *start_p = reader->type_pos;

1132  *len_p = find_len_of_complete_type (reader->type_str, reader->type_pos);

1133 }

1134

typedef struct

1136 {

1140

1142 replacement_block_init (ReplacementBlock *block,

1144 {

1146  return FALSE;

1147

1148  /* % 8 is the padding to have the same align properties in

1149 * our replacement string as we do at the position being replaced

1150 */

1151  block->padding = reader->value_pos % 8;

1152

1154  goto oom;

1155

1156  return TRUE;

1157

1158  oom:

1160  return FALSE;

1161 }

1162

1164 replacement_block_replace (ReplacementBlock *block,

1166  const DBusTypeReader *realign_root)

1167 {

1169  DBusTypeReader realign_reader;

1170  DBusList *fixups;

1171  int orig_len;

1172

1173  _dbus_assert (realign_root != NULL);

1174

1175  orig_len = _dbus_string_get_length (&block->replacement);

1176

1177  realign_reader = *realign_root;

1178

1179 #if RECURSIVE_MARSHAL_WRITE_TRACE

1180  _dbus_verbose ("INITIALIZING replacement block writer %p at value_pos %d\n",

1181  &writer, _dbus_string_get_length (&block->replacement));

1182 #endif

1184  realign_reader.byte_order,

1185  realign_reader.type_str,

1186  realign_reader.type_pos,

1187  &block->replacement,

1188  _dbus_string_get_length (&block->replacement));

1189

1190  _dbus_assert (realign_reader.value_pos <= reader->value_pos);

1191

1192 #if RECURSIVE_MARSHAL_WRITE_TRACE

1193  _dbus_verbose ("COPYING from reader at value_pos %d to writer %p starting after value_pos %d\n",

1194  realign_reader.value_pos, &writer, reader->value_pos);

1195 #endif

1196  fixups = NULL;

1197  if (!_dbus_type_writer_write_reader_partial (&writer,

1198  &realign_reader,

1199  reader,

1200  block->padding,

1201  _dbus_string_get_length (&block->replacement) - block->padding,

1202  &fixups))

1203  goto oom;

1204

1205 #if RECURSIVE_MARSHAL_WRITE_TRACE

1206  _dbus_verbose ("REPLACEMENT at padding %d len %d\n", block->padding,

1207  _dbus_string_get_length (&block->replacement) - block->padding);

1209  _dbus_string_get_length (&block->replacement) - block->padding);

1210  _dbus_verbose ("TO BE REPLACED at value_pos = %d (align pad %d) len %d realign_reader.value_pos %d\n",

1211  reader->value_pos, reader->value_pos % 8,

1212  realign_reader.value_pos - reader->value_pos,

1213  realign_reader.value_pos);

1215  reader->value_pos,

1216  realign_reader.value_pos - reader->value_pos);

1217 #endif

1218

1219  /* Move the replacement into position

1220 * (realign_reader should now be at the end of the block to be replaced)

1221 */

1223  _dbus_string_get_length (&block->replacement) - block->padding,

1225  reader->value_pos,

1226  realign_reader.value_pos - reader->value_pos))

1227  goto oom;

1228

1229  /* Process our fixups now that we can't have an OOM error */

1230  apply_and_free_fixups (&fixups, reader);

1231

1232  return TRUE;

1233

1234  oom:

1236  free_fixups (&fixups);

1237  return FALSE;

1238 }

1239

1240 static void

1241 replacement_block_free (ReplacementBlock *block)

1242 {

1244 }

1245

1246 /* In the variable-length case, we have to fix alignment after we insert.

1247 * The strategy is as follows:

1248 *

1249 * - pad a new string to have the same alignment as the

1250 * start of the current basic value

1251 * - write the new basic value

1252 * - copy from the original reader to the new string,

1253 * which will fix the alignment of types following

1254 * the new value

1255 * - this copy has to start at realign_root,

1256 * but not really write anything until it

1257 * passes the value being set

1258 * - as an optimization, we can stop copying

1259 * when the source and dest values are both

1260 * on an 8-boundary, since we know all following

1261 * padding and alignment will be identical

1262 * - copy the new string back to the original

1263 * string, replacing the relevant part of the

1264 * original string

1265 * - now any arrays in the original string that

1266 * contained the replaced string may have the

1267 * wrong length; so we have to fix that

1268 */

1270 reader_set_basic_variable_length (DBusTypeReader *reader,

1271  int current_type,

1272  const void *value,

1273  const DBusTypeReader *realign_root)

1274 {

1275  dbus_bool_t retval;

1278

1279  _dbus_assert (realign_root != NULL);

1280

1281  retval = FALSE;

1282

1283  if (!replacement_block_init (&block, reader))

1284  return FALSE;

1285

1286  /* Write the new basic value */

1287 #if RECURSIVE_MARSHAL_WRITE_TRACE

1288  _dbus_verbose ("INITIALIZING writer %p to write basic value at value_pos %d of replacement string\n",

1289  &writer, _dbus_string_get_length (&block.replacement));

1290 #endif

1292  reader->byte_order,

1293  reader->type_str,

1294  reader->type_pos,

1295  &block.replacement,

1296  _dbus_string_get_length (&block.replacement));

1297 #if RECURSIVE_MARSHAL_WRITE_TRACE

1298  _dbus_verbose ("WRITING basic value to writer %p (replacement string)\n", &writer);

1299 #endif

1300  if (!_dbus_type_writer_write_basic (&writer, current_type, value))

1301  goto out;

1302

1303  if (!replacement_block_replace (&block,

1304  reader,

1305  realign_root))

1306  goto out;

1307

1308  retval = TRUE;

1309

1310  out:

1311  replacement_block_free (&block);

1312  return retval;

1313 }

1314

1315 static void

1316 reader_set_basic_fixed_length (DBusTypeReader *reader,

1317  int current_type,

1318  const void *value)

1319 {

1321  reader->value_pos,

1322  current_type,

1323  value,

1324  reader->byte_order,

1326 }

1327

1364  const void *value,

1365  const DBusTypeReader *realign_root)

1366 {

1367  int current_type;

1368

1370  _dbus_assert (reader->value_str == realign_root->value_str);

1371  _dbus_assert (reader->value_pos >= realign_root->value_pos);

1372

1374

1375 #if RECURSIVE_MARSHAL_WRITE_TRACE

1376  _dbus_verbose (" SET BASIC type reader %p type_pos = %d value_pos = %d remaining sig '%s' realign_root = %p with value_pos %d current_type = %s\n",

1377  reader, reader->type_pos, reader->value_pos,

1378  _dbus_string_get_const_data_len (reader->type_str, reader->type_pos, 0),

1379  realign_root,

1380  realign_root ? realign_root->value_pos : -1,

1381  _dbus_type_to_string (current_type));

1383  _dbus_string_get_length (realign_root->value_str) -

1384  realign_root->value_pos);

1385 #endif

1386

1388

1389  if (dbus_type_is_fixed (current_type))

1390  {

1391  reader_set_basic_fixed_length (reader, current_type, value);

1392  return TRUE;

1393  }

1394  else

1395  {

1396  _dbus_assert (realign_root != NULL);

1397  return reader_set_basic_variable_length (reader, current_type,

1398  value, realign_root);

1399  }

1400 }

1401

1421  const DBusTypeReader *realign_root)

1422 {

1423  dbus_bool_t retval;

1425

1426  _dbus_assert (realign_root != NULL);

1427  _dbus_assert (reader->klass == &array_reader_class);

1428

1429  retval = FALSE;

1430

1431  if (!replacement_block_init (&block, reader))

1432  return FALSE;

1433

1434  if (!replacement_block_replace (&block,

1435  reader,

1436  realign_root))

1437  goto out;

1438

1439  retval = TRUE;

1440

1441  out:

1442  replacement_block_free (&block);

1443  return retval;

1444 }

1445

1446 /*

1447 * Compares two readers, which must be iterating over the same value data.

1448 * Returns #TRUE if the first parameter is further along than the second parameter.

1449 *

1450 * @param lhs left-hand-side (first) parameter

1451 * @param rhs left-hand-side (first) parameter

1452 * @returns whether lhs is greater than rhs

1453 */

1455 _dbus_type_reader_greater_than (const DBusTypeReader *lhs,

1456  const DBusTypeReader *rhs)

1457 {

1459

1460  return lhs->value_pos > rhs->value_pos;

1461 }

1462

1463 /*

1464 *

1465 *

1466 * DBusTypeWriter

1467 *

1468 *

1469 *

1470 */

1471

1492 void

1494  int byte_order,

1495  DBusString *type_str,

1496  int type_pos,

1497  DBusString *value_str,

1498  int value_pos)

1499 {

1500  writer->byte_order = byte_order;

1501  writer->type_str = type_str;

1502  writer->type_pos = type_pos;

1503  writer->value_str = value_str;

1504  writer->value_pos = value_pos;

1507  writer->enabled = TRUE;

1508

1509 #if RECURSIVE_MARSHAL_WRITE_TRACE

1510  _dbus_verbose ("writer %p init remaining sig '%s'\n", writer,

1511  writer->type_str ?

1512  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :

1513  "unknown");

1514 #endif

1515 }

1516

1527 void

1529  int byte_order,

1530  DBusString *value_str,

1531  int value_pos)

1532 {

1533  _dbus_type_writer_init (writer, byte_order,

1534  NULL, 0, value_str, value_pos);

1535 }

1536

1545 void

1547  DBusString *type_str,

1548  int type_pos)

1549 {

1550  if (writer->type_str == NULL) /* keeps us from using this as setter */

1551  {

1552  writer->type_str = type_str;

1553  writer->type_pos = type_pos;

1554  }

1555 }

1556

1562 void

1564 {

1565  writer->type_str = NULL;

1566  writer->type_pos = -1;

1567 }

1568

1583 void

1585  int byte_order,

1586  const DBusString *type_str,

1587  int type_pos,

1588  DBusString *value_str,

1589  int value_pos)

1590 {

1591  _dbus_type_writer_init (writer, byte_order,

1592  (DBusString*)type_str, type_pos,

1593  value_str, value_pos);

1594

1596 }

1597

1599 _dbus_type_writer_write_basic_no_typecode (DBusTypeWriter *writer,

1600  int type,

1601  const void *value)

1602 {

1603  if (writer->enabled)

1605  writer->value_pos,

1606  type,

1607  value,

1608  writer->byte_order,

1609  &writer->value_pos);

1610  else

1611  return TRUE;

1612 }

1613

1614 /* If our parent is an array, things are a little bit complicated.

1615 *

1616 * The parent must have a complete element type, such as

1617 * "i" or "aai" or "(ii)" or "a(ii)". There can't be

1618 * unclosed parens, or an "a" with no following type.

1619 *

1620 * To recurse, the only allowed operation is to recurse into the

1621 * first type in the element type. So for "i" you can't recurse, for

1622 * "ai" you can recurse into the array, for "(ii)" you can recurse

1623 * into the struct.

1624 *

1625 * If you recurse into the array for "ai", then you must specify

1626 * "i" for the element type of the array you recurse into.

1627 *

1628 * While inside an array at any level, we need to avoid writing to

1629 * type_str, since the type only appears once for the whole array,

1630 * it does not appear for each array element.

1631 *

1632 * While inside an array type_pos points to the expected next

1633 * typecode, rather than the next place we could write a typecode.

1634 */

1635 static void

1636 writer_recurse_init_and_check (DBusTypeWriter *writer,

1637  int container_type,

1639 {

1641  writer->byte_order,

1642  writer->type_str,

1643  writer->type_pos,

1644  writer->value_str,

1645  writer->value_pos);

1646

1647  sub->container_type = container_type;

1648

1652  else

1654

1655  sub->enabled = writer->enabled;

1656

1657 #ifndef DBUS_DISABLE_CHECKS

1659  {

1660  int expected;

1661

1663

1664  if (expected != sub->container_type)

1665  {

1666  if (expected != DBUS_TYPE_INVALID)

1667  _dbus_warn_check_failed ("Writing an element of type %s, but the expected type here is %s\n"

1668  "The overall signature expected here was '%s' and we are on byte %d of that signature.",

1671  _dbus_string_get_const_data (writer->type_str), writer->type_pos);

1672  else

1673  _dbus_warn_check_failed ("Writing an element of type %s, but no value is expected here\n"

1674  "The overall signature expected here was '%s' and we are on byte %d of that signature.",

1676  _dbus_string_get_const_data (writer->type_str), writer->type_pos);

1677

1678  _dbus_assert_not_reached ("bad array element or variant content written");

1679  }

1680  }

1681 #endif/* DBUS_DISABLE_CHECKS */

1682

1683 #if RECURSIVE_MARSHAL_WRITE_TRACE

1684  _dbus_verbose (" type writer %p recurse parent %s type_pos = %d value_pos = %d is_expectation = %d remaining sig '%s' enabled = %d\n",

1685  writer,

1688  writer->type_str ?

1689  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :

1690  "unknown",

1691  writer->enabled);

1692  _dbus_verbose (" type writer %p recurse sub %s type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",

1693  sub,

1695  sub->type_pos, sub->value_pos,

1697  sub->enabled);

1698 #endif

1699 }

1700

1702 write_or_verify_typecode (DBusTypeWriter *writer,

1703  int typecode)

1704 {

1705  /* A subwriter inside an array or variant will have type_pos

1706 * pointing to the expected typecode; a writer not inside an array

1707 * or variant has type_pos pointing to the next place to insert a

1708 * typecode.

1709 */

1710 #if RECURSIVE_MARSHAL_WRITE_TRACE

1711  _dbus_verbose (" type writer %p write_or_verify start type_pos = %d remaining sig '%s' enabled = %d\n",

1712  writer, writer->type_pos,

1713  writer->type_str ?

1714  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :

1715  "unknown",

1716  writer->enabled);

1717 #endif

1718

1719  if (writer->type_str == NULL)

1720  return TRUE;

1721

1723  {

1724 #ifndef DBUS_DISABLE_CHECKS

1725  {

1726  int expected;

1727

1728  expected = _dbus_string_get_byte (writer->type_str, writer->type_pos);

1729

1730  if (expected != typecode)

1731  {

1732  if (expected != DBUS_TYPE_INVALID)

1733  _dbus_warn_check_failed ("Array or variant type requires that type %s be written, but %s was written.\n"

1734  "The overall signature expected here was '%s' and we are on byte %d of that signature.",

1736  _dbus_string_get_const_data (writer->type_str), writer->type_pos);

1737  else

1738  _dbus_warn_check_failed ("Array or variant type wasn't expecting any more values to be written into it, but a value %s was written.\n"

1739  "The overall signature expected here was '%s' and we are on byte %d of that signature.",

1741  _dbus_string_get_const_data (writer->type_str), writer->type_pos);

1742  _dbus_assert_not_reached ("bad type inserted somewhere inside an array or variant");

1743  }

1744  }

1745 #endif/* DBUS_DISABLE_CHECKS */

1746

1747  /* if immediately inside an array we'd always be appending an element,

1748 * so the expected type doesn't change; if inside a struct or something

1749 * below an array, we need to move through said struct or something.

1750 */

1752  writer->type_pos += 1;

1753  }

1754  else

1755  {

1757  writer->type_pos,

1758  typecode))

1759  return FALSE;

1760

1761  writer->type_pos += 1;

1762  }

1763

1764 #if RECURSIVE_MARSHAL_WRITE_TRACE

1765  _dbus_verbose (" type writer %p write_or_verify end type_pos = %d remaining sig '%s'\n",

1766  writer, writer->type_pos,

1767  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0));

1768 #endif

1769

1770  return TRUE;

1771 }

1772

1774 writer_recurse_struct_or_dict_entry (DBusTypeWriter *writer,

1775  int begin_char,

1776  const DBusString *contained_type,

1777  int contained_type_start,

1778  int contained_type_len,

1780 {

1781  /* FIXME right now contained_type is ignored; we could probably

1782 * almost trivially fix the code so if it's present we

1783 * write it out and then set type_pos_is_expectation

1784 */

1785

1786  /* Ensure that we'll be able to add alignment padding and the typecode */

1787  if (writer->enabled)

1788  {

1790  return FALSE;

1791  }

1792

1793  if (!write_or_verify_typecode (sub, begin_char))

1794  _dbus_assert_not_reached ("failed to insert struct typecode after prealloc");

1795

1796  if (writer->enabled)

1797  {

1799  sub->value_pos,

1800  _DBUS_ALIGN_VALUE (sub->value_pos, 8) - sub->value_pos,

1801  '\0'))

1802  _dbus_assert_not_reached ("should not have failed to insert alignment padding for struct");

1803  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 8);

1804  }

1805

1806  return TRUE;

1807 }

1808

1809

1811 writer_recurse_array (DBusTypeWriter *writer,

1812  const DBusString *contained_type,

1813  int contained_type_start,

1814  int contained_type_len,

1816  dbus_bool_t is_array_append)

1817 {

1818  dbus_uint32_t value = 0;

1819  int alignment;

1820  int aligned;

1821

1822 #ifndef DBUS_DISABLE_CHECKS

1824  writer->type_str)

1825  {

1827  contained_type_start,

1828  contained_type_len,

1829  writer->type_str,

1830  writer->u.array.element_type_pos + 1))

1831  {

1832  _dbus_warn_check_failed ("Writing an array of '%s' but this is incompatible with the expected type of elements in the parent array",

1833  _dbus_string_get_const_data_len (contained_type,

1834  contained_type_start,

1835  contained_type_len));

1836  _dbus_assert_not_reached ("incompatible type for child array");

1837  }

1838  }

1839 #endif/* DBUS_DISABLE_CHECKS */

1840

1841  if (writer->enabled && !is_array_append)

1842  {

1843  /* 3 pad + 4 bytes for the array length, and 4 bytes possible padding

1844 * before array values

1845 */

1847  return FALSE;

1848  }

1849

1850  if (writer->type_str != NULL)

1851  {

1852  sub->type_pos += 1; /* move to point to the element type, since type_pos

1853 * should be the expected type for further writes

1854 */

1855  sub->u.array.element_type_pos = sub->type_pos;

1856  }

1857

1859  {

1860  /* sub is a toplevel/outermost array so we need to write the type data */

1861

1862  /* alloc space for array typecode, element signature */

1863  if (!_dbus_string_alloc_space (writer->type_str, 1 + contained_type_len))

1864  return FALSE;

1865

1867  writer->type_pos,

1869  _dbus_assert_not_reached ("failed to insert array typecode after prealloc");

1870

1871  if (!_dbus_string_copy_len (contained_type,

1872  contained_type_start, contained_type_len,

1873  sub->type_str,

1874  sub->u.array.element_type_pos))

1875  _dbus_assert_not_reached ("should not have failed to insert array element typecodes");

1876  }

1877

1878  if (writer->type_str != NULL)

1879  {

1880  /* If the parent is an array, we hold type_pos pointing at the array element type;

1881 * otherwise advance it to reflect the array value we just recursed into

1882 */

1884  writer->type_pos += 1 + contained_type_len;

1885  else

1886  _dbus_assert (writer->type_pos_is_expectation); /* because it's an array */

1887  }

1888

1889  if (writer->enabled)

1890  {

1891  /* Write (or jump over, if is_array_append) the length */

1892  sub->u.array.len_pos = _DBUS_ALIGN_VALUE (sub->value_pos, 4);

1893

1894  if (is_array_append)

1895  {

1896  sub->value_pos += 4;

1897  }

1898  else

1899  {

1900  if (!_dbus_type_writer_write_basic_no_typecode (sub, DBUS_TYPE_UINT32,

1901  &value))

1902  _dbus_assert_not_reached ("should not have failed to insert array len");

1903  }

1904

1905  _dbus_assert (sub->u.array.len_pos == sub->value_pos - 4);

1906

1907  /* Write alignment padding for array elements

1908 * Note that we write the padding *even for empty arrays*

1909 * to avoid wonky special cases

1910 */

1911  alignment = element_type_get_alignment (contained_type, contained_type_start);

1912

1913  aligned = _DBUS_ALIGN_VALUE (sub->value_pos, alignment);

1914  if (aligned != sub->value_pos)

1915  {

1916  if (!is_array_append)

1917  {

1919  sub->value_pos,

1920  aligned - sub->value_pos,

1921  '\0'))

1922  _dbus_assert_not_reached ("should not have failed to insert alignment padding");

1923  }

1924

1925  sub->value_pos = aligned;

1926  }

1927

1928  sub->u.array.start_pos = sub->value_pos;

1929

1930  if (is_array_append)

1931  {

1932  dbus_uint32_t len;

1933

1934  _dbus_assert (_DBUS_ALIGN_VALUE (sub->u.array.len_pos, 4) ==

1935  (unsigned) sub->u.array.len_pos);

1937  _dbus_string_get_const_udata_len (sub->value_str,

1938  sub->u.array.len_pos,

1939  4));

1940

1941  sub->value_pos += len;

1942  }

1943  }

1944  else

1945  {

1946  /* not enabled, so we won't write the len_pos; set it to -1 to so indicate */

1947  sub->u.array.len_pos = -1;

1948  sub->u.array.start_pos = sub->value_pos;

1949  }

1950

1951  _dbus_assert (sub->u.array.len_pos < sub->u.array.start_pos);

1952  _dbus_assert (is_array_append || sub->u.array.start_pos == sub->value_pos);

1953

1954 #if RECURSIVE_MARSHAL_WRITE_TRACE

1955  _dbus_verbose (" type writer %p recurse array done remaining sig '%s' array start_pos = %d len_pos = %d value_pos = %d\n", sub,

1956  sub->type_str ?

1957  _dbus_string_get_const_data_len (sub->type_str, sub->type_pos, 0) :

1958  "unknown",

1959  sub->u.array.start_pos, sub->u.array.len_pos, sub->value_pos);

1960 #endif

1961

1962  return TRUE;

1963 }

1964

1965 /* Variant value will normally have:

1966 * 1 byte signature length not including nul

1967 * signature typecodes (nul terminated)

1968 * padding to alignment of contained type

1969 * body according to signature

1970 *

1971 * The signature string can only have a single type

1972 * in it but that type may be complex/recursive.

1973 *

1974 * So a typical variant type with the integer 3 will have these

1975 * octets:

1976 * 0x1 'i' '\0' [1 byte padding to alignment boundary] 0x0 0x0 0x0 0x3

1977 *

1978 * The main world of hurt for writing out a variant is that the type

1979 * string is the same string as the value string. Which means

1980 * inserting to the type string will move the value_pos; and it means

1981 * that inserting to the type string could break type alignment.

1982 */

1984 writer_recurse_variant (DBusTypeWriter *writer,

1985  const DBusString *contained_type,

1986  int contained_type_start,

1987  int contained_type_len,

1989 {

1990  int contained_alignment;

1991

1992  if (writer->enabled)

1993  {

1994  /* Allocate space for the worst case, which is 1 byte sig

1995 * length, nul byte at end of sig, and 7 bytes padding to

1996 * 8-boundary.

1997 */

1998  if (!_dbus_string_alloc_space (sub->value_str, contained_type_len + 9))

1999  return FALSE;

2000  }

2001

2002  /* write VARIANT typecode to the parent's type string */

2003  if (!write_or_verify_typecode (writer, DBUS_TYPE_VARIANT))

2004  return FALSE;

2005

2006  /* If not enabled, mark that we have no type_str anymore ... */

2007

2008  if (!writer->enabled)

2009  {

2011  sub->type_pos = -1;

2012

2013  return TRUE;

2014  }

2015

2016  /* If we're enabled then continue ... */

2017

2019  sub->value_pos,

2020  contained_type_len))

2021  _dbus_assert_not_reached ("should not have failed to insert variant type sig len");

2022

2023  sub->value_pos += 1;

2024

2025  /* Here we switch over to the expected type sig we're about to write */

2026  sub->type_str = sub->value_str;

2027  sub->type_pos = sub->value_pos;

2028

2029  if (!_dbus_string_copy_len (contained_type, contained_type_start, contained_type_len,

2030  sub->value_str, sub->value_pos))

2031  _dbus_assert_not_reached ("should not have failed to insert variant type sig");

2032

2033  sub->value_pos += contained_type_len;

2034

2036  sub->value_pos,

2038  _dbus_assert_not_reached ("should not have failed to insert variant type nul termination");

2039

2040  sub->value_pos += 1;

2041

2042  contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (contained_type, contained_type_start));

2043

2045  sub->value_pos,

2046  _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment) - sub->value_pos,

2047  '\0'))

2048  _dbus_assert_not_reached ("should not have failed to insert alignment padding for variant body");

2049  sub->value_pos = _DBUS_ALIGN_VALUE (sub->value_pos, contained_alignment);

2050

2051  return TRUE;

2052 }

2053

2055 _dbus_type_writer_recurse_contained_len (DBusTypeWriter *writer,

2056  int container_type,

2057  const DBusString *contained_type,

2058  int contained_type_start,

2059  int contained_type_len,

2061  dbus_bool_t is_array_append)

2062 {

2063  writer_recurse_init_and_check (writer, container_type, sub);

2064

2065  switch (container_type)

2066  {

2068  return writer_recurse_struct_or_dict_entry (writer,

2070  contained_type,

2071  contained_type_start, contained_type_len,

2072  sub);

2073  break;

2075  return writer_recurse_struct_or_dict_entry (writer,

2077  contained_type,

2078  contained_type_start, contained_type_len,

2079  sub);

2080  break;

2082  return writer_recurse_array (writer,

2083  contained_type, contained_type_start, contained_type_len,

2084  sub, is_array_append);

2085  break;

2087  return writer_recurse_variant (writer,

2088  contained_type, contained_type_start, contained_type_len,

2089  sub);

2090  break;

2091  default:

2092  _dbus_assert_not_reached ("tried to recurse into type that doesn't support that");

2093  return FALSE;

2094  break;

2095  }

2096 }

2097

2110  int container_type,

2111  const DBusString *contained_type,

2112  int contained_type_start,

2114 {

2115  int contained_type_len;

2116

2117  if (contained_type)

2118  contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);

2119  else

2120  contained_type_len = 0;

2121

2122  return _dbus_type_writer_recurse_contained_len (writer, container_type,

2123  contained_type,

2124  contained_type_start,

2125  contained_type_len,

2126  sub,

2127  FALSE);

2128 }

2129

2144  const DBusString *contained_type,

2145  int contained_type_start,

2147 {

2148  int contained_type_len;

2149

2150  if (contained_type)

2151  contained_type_len = find_len_of_complete_type (contained_type, contained_type_start);

2152  else

2153  contained_type_len = 0;

2154

2155  return _dbus_type_writer_recurse_contained_len (writer, DBUS_TYPE_ARRAY,

2156  contained_type,

2157  contained_type_start,

2158  contained_type_len,

2159  sub,

2160  TRUE);

2161 }

2162

2163 static int

2164 writer_get_array_len (DBusTypeWriter *writer)

2165 {

2167  return writer->value_pos - writer->u.array.start_pos;

2168 }

2169

2181 {

2182  /* type_pos_is_expectation never gets unset once set, or we'd get all hosed */

2185

2186 #if RECURSIVE_MARSHAL_WRITE_TRACE

2187  _dbus_verbose (" type writer %p unrecurse type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",

2188  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,

2190  _dbus_verbose (" type writer %p unrecurse sub type_pos = %d value_pos = %d is_expectation = %d container_type = %s\n",

2191  sub, sub->type_pos, sub->value_pos,

2194 #endif

2195

2197  {

2198  if (!write_or_verify_typecode (sub, DBUS_STRUCT_END_CHAR))

2199  return FALSE;

2200  }

2202  {

2203  if (!write_or_verify_typecode (sub, DBUS_DICT_ENTRY_END_CHAR))

2204  return FALSE;

2205  }

2207  {

2208  if (sub->u.array.len_pos >= 0) /* len_pos == -1 if we weren't enabled when we passed it */

2209  {

2210  dbus_uint32_t len;

2211

2212  /* Set the array length */

2213  len = writer_get_array_len (sub);

2215  sub->u.array.len_pos,

2216  len,

2217  sub->byte_order);

2218 #if RECURSIVE_MARSHAL_WRITE_TRACE

2219  _dbus_verbose (" filled in sub array len to %u at len_pos %d\n",

2220  len, sub->u.array.len_pos);

2221 #endif

2222  }

2223 #if RECURSIVE_MARSHAL_WRITE_TRACE

2224  else

2225  {

2226  _dbus_verbose (" not filling in sub array len because we were disabled when we passed the len\n");

2227  }

2228 #endif

2229  }

2230

2231  /* Now get type_pos right for the parent writer. Here are the cases:

2232 *

2233 * Cases !writer->type_pos_is_expectation:

2234 * (in these cases we want to update to the new insertion point)

2235 *

2236 * - if we recursed into a STRUCT then we didn't know in advance

2237 * what the types in the struct would be; so we have to fill in

2238 * that information now.

2239 * writer->type_pos = sub->type_pos

2240 *

2241 * - if we recursed into anything else, we knew the full array

2242 * type, or knew the single typecode marking VARIANT, so

2243 * writer->type_pos is already correct.

2244 * writer->type_pos should remain as-is

2245 *

2246 * - note that the parent is never an ARRAY or VARIANT, if it were

2247 * then type_pos_is_expectation would be TRUE. The parent

2248 * is thus known to be a toplevel or STRUCT.

2249 *

2250 * Cases where writer->type_pos_is_expectation:

2251 * (in these cases we want to update to next expected type to write)

2252 *

2253 * - we recursed from STRUCT into STRUCT and we didn't increment

2254 * type_pos in the parent just to stay consistent with the

2255 * !writer->type_pos_is_expectation case (though we could

2256 * special-case this in recurse_struct instead if we wanted)

2257 * writer->type_pos = sub->type_pos

2258 *

2259 * - we recursed from STRUCT into ARRAY or VARIANT and type_pos

2260 * for parent should have been incremented already

2261 * writer->type_pos should remain as-is

2262 *

2263 * - we recursed from ARRAY into a sub-element, so type_pos in the

2264 * parent is the element type and should remain the element type

2265 * for the benefit of the next child element

2266 * writer->type_pos should remain as-is

2267 *

2268 * - we recursed from VARIANT into its value, so type_pos in the

2269 * parent makes no difference since there's only one value

2270 * and we just finished writing it and won't use type_pos again

2271 * writer->type_pos should remain as-is

2272 *

2273 *

2274 * For all these, DICT_ENTRY is the same as STRUCT

2275 */

2276  if (writer->type_str != NULL)

2277  {

2283  {

2284  /* Advance the parent to the next struct field */

2285  writer->type_pos = sub->type_pos;

2286  }

2287  }

2288

2289  writer->value_pos = sub->value_pos;

2290

2291 #if RECURSIVE_MARSHAL_WRITE_TRACE

2292  _dbus_verbose (" type writer %p unrecursed type_pos = %d value_pos = %d remaining sig '%s'\n",

2293  writer, writer->type_pos, writer->value_pos,

2294  writer->type_str ?

2295  _dbus_string_get_const_data_len (writer->type_str, writer->type_pos, 0) :

2296  "unknown");

2297 #endif

2298

2299  return TRUE;

2300 }

2301

2312  int type,

2313  const void *value)

2314 {

2315  dbus_bool_t retval;

2316

2317  /* First ensure that our type realloc will succeed */

2319  {

2321  return FALSE;

2322  }

2323

2324  retval = FALSE;

2325

2326  if (!_dbus_type_writer_write_basic_no_typecode (writer, type, value))

2327  goto out;

2328

2329  if (!write_or_verify_typecode (writer, type))

2330  _dbus_assert_not_reached ("failed to write typecode after prealloc");

2331

2332  retval = TRUE;

2333

2334  out:

2335 #if RECURSIVE_MARSHAL_WRITE_TRACE

2336  _dbus_verbose (" type writer %p basic type_pos = %d value_pos = %d is_expectation = %d enabled = %d\n",

2337  writer, writer->type_pos, writer->value_pos, writer->type_pos_is_expectation,

2338  writer->enabled);

2339 #endif

2340

2341  return retval;

2342 }

2343

2360  int element_type,

2361  const void *value,

2362  int n_elements)

2363 {

2367  _dbus_assert (n_elements >= 0);

2368

2369 #if RECURSIVE_MARSHAL_WRITE_TRACE

2370  _dbus_verbose (" type writer %p entering fixed multi type_pos = %d value_pos = %d n_elements %d\n",

2371  writer, writer->type_pos, writer->value_pos, n_elements);

2372 #endif

2373

2374  if (!write_or_verify_typecode (writer, element_type))

2375  _dbus_assert_not_reached ("OOM should not happen if only verifying typecode");

2376

2377  if (writer->enabled)

2378  {

2380  writer->value_pos,

2381  element_type,

2382  value,

2383  n_elements,

2384  writer->byte_order,

2385  &writer->value_pos))

2386  return FALSE;

2387  }

2388

2389 #if RECURSIVE_MARSHAL_WRITE_TRACE

2390  _dbus_verbose (" type writer %p fixed multi written new type_pos = %d new value_pos = %d n_elements %d\n",

2391  writer, writer->type_pos, writer->value_pos, n_elements);

2392 #endif

2393

2394  return TRUE;

2395 }

2396

2397 static void

2398 enable_if_after (DBusTypeWriter *writer,

2400  const DBusTypeReader *start_after)

2401 {

2402  if (start_after)

2403  {

2404  if (!writer->enabled && _dbus_type_reader_greater_than (reader, start_after))

2405  {

2406  _dbus_type_writer_set_enabled (writer, TRUE);

2407 #if RECURSIVE_MARSHAL_WRITE_TRACE

2408  _dbus_verbose ("ENABLING writer %p at %d because reader at value_pos %d is after reader at value_pos %d\n",

2409  writer, writer->value_pos, reader->value_pos, start_after->value_pos);

2410 #endif

2411  }

2412

2413  _dbus_assert ((!writer->enabled && !_dbus_type_reader_greater_than (reader, start_after)) ||

2414  (writer->enabled && _dbus_type_reader_greater_than (reader, start_after)));

2415  }

2416 }

2417

2419 append_fixup (DBusList **fixups,

2421 {

2423

2425  if (f == NULL)

2426  return FALSE;

2427

2428  *f = *fixup;

2429

2430  if (!_dbus_list_append (fixups, f))

2431  {

2433  return FALSE;

2434  }

2435

2438

2439  return TRUE;

2440 }

2441

2442 /* This loop is trivial if you ignore all the start_after nonsense,

2443 * so if you're trying to figure it out, start by ignoring that

2444 */

2446 writer_write_reader_helper (DBusTypeWriter *writer,

2448  const DBusTypeReader *start_after,

2449  int start_after_new_pos,

2450  int start_after_new_len,

2451  DBusList **fixups,

2452  dbus_bool_t inside_start_after)

2453 {

2454  int current_type;

2455

2457  {

2458  if (dbus_type_is_container (current_type))

2459  {

2460  DBusTypeReader subreader;

2461  DBusTypeWriter subwriter;

2462  const DBusString *sig_str;

2463  int sig_start;

2464  int sig_len;

2465  dbus_bool_t enabled_at_recurse;

2466  dbus_bool_t past_start_after;

2467  int reader_array_len_pos;

2468  int reader_array_start_pos;

2469  dbus_bool_t this_is_start_after;

2470

2471  /* type_pos is checked since e.g. in a struct the struct

2472 * and its first field have the same value_pos.

2473 * type_str will differ in reader/start_after for variants

2474 * where type_str is inside the value_str

2475 */

2476  if (!inside_start_after && start_after &&

2477  reader->value_pos == start_after->value_pos &&

2478  reader->type_str == start_after->type_str &&

2479  reader->type_pos == start_after->type_pos)

2480  this_is_start_after = TRUE;

2481  else

2482  this_is_start_after = FALSE;

2483

2484  _dbus_type_reader_recurse (reader, &subreader);

2485

2486  if (current_type == DBUS_TYPE_ARRAY)

2487  {

2488  reader_array_len_pos = ARRAY_READER_LEN_POS (&subreader);

2489  reader_array_start_pos = subreader.u.array.start_pos;

2490  }

2491  else

2492  {

2493  /* quiet gcc */

2494  reader_array_len_pos = -1;

2495  reader_array_start_pos = -1;

2496  }

2497

2499  &sig_start, &sig_len);

2500

2501 #if RECURSIVE_MARSHAL_WRITE_TRACE

2502  _dbus_verbose ("about to recurse into %s reader at %d subreader at %d writer at %d start_after reader at %d write target len %d inside_start_after = %d this_is_start_after = %d\n",

2504  reader->value_pos,

2505  subreader.value_pos,

2506  writer->value_pos,

2507  start_after ? start_after->value_pos : -1,

2508  _dbus_string_get_length (writer->value_str),

2509  inside_start_after, this_is_start_after);

2510 #endif

2511

2512  if (!inside_start_after && !this_is_start_after)

2513  enable_if_after (writer, &subreader, start_after);

2514  enabled_at_recurse = writer->enabled;

2515  if (!_dbus_type_writer_recurse_contained_len (writer, current_type,

2516  sig_str, sig_start, sig_len,

2517  &subwriter, FALSE))

2518  goto oom;

2519

2520 #if RECURSIVE_MARSHAL_WRITE_TRACE

2521  _dbus_verbose ("recursed into subwriter at %d write target len %d\n",

2522  subwriter.value_pos,

2523  _dbus_string_get_length (subwriter.value_str));

2524 #endif

2525

2526  if (!writer_write_reader_helper (&subwriter, &subreader, start_after,

2527  start_after_new_pos, start_after_new_len,

2528  fixups,

2529  inside_start_after ||

2530  this_is_start_after))

2531  goto oom;

2532

2533 #if RECURSIVE_MARSHAL_WRITE_TRACE

2534  _dbus_verbose ("about to unrecurse from %s subreader at %d writer at %d subwriter at %d write target len %d\n",

2536  subreader.value_pos,

2537  writer->value_pos,

2538  subwriter.value_pos,

2539  _dbus_string_get_length (writer->value_str));

2540 #endif

2541

2542  if (!inside_start_after && !this_is_start_after)

2543  enable_if_after (writer, &subreader, start_after);

2544  past_start_after = writer->enabled;

2545  if (!_dbus_type_writer_unrecurse (writer, &subwriter))

2546  goto oom;

2547

2548  /* If we weren't enabled when we recursed, we didn't

2549 * write an array len; if we passed start_after

2550 * somewhere inside the array, then we need to generate

2551 * a fixup.

2552 */

2553  if (start_after != NULL &&

2554  !enabled_at_recurse && past_start_after &&

2555  current_type == DBUS_TYPE_ARRAY &&

2556  fixups != NULL)

2557  {

2559  int bytes_written_after_start_after;

2560  int bytes_before_start_after;

2561  int old_len;

2562

2563  /* this subwriter access is moderately unkosher since we

2564 * already unrecursed, but it works as long as unrecurse

2565 * doesn't break us on purpose

2566 */

2567  bytes_written_after_start_after = writer_get_array_len (&subwriter);

2568

2569  bytes_before_start_after =

2570  start_after->value_pos - reader_array_start_pos;

2571

2572  fixup.len_pos_in_reader = reader_array_len_pos;

2573  fixup.new_len =

2574  bytes_before_start_after +

2575  start_after_new_len +

2576  bytes_written_after_start_after;

2577

2578  _dbus_assert (_DBUS_ALIGN_VALUE (fixup.len_pos_in_reader, 4) ==

2579  (unsigned) fixup.len_pos_in_reader);

2580

2582  _dbus_string_get_const_udata_len (reader->value_str,

2584

2585  if (old_len != fixup.new_len && !append_fixup (fixups, &fixup))

2586  goto oom;

2587

2588 #if RECURSIVE_MARSHAL_WRITE_TRACE

2589  _dbus_verbose ("Generated fixup len_pos_in_reader = %d new_len = %d reader_array_start_pos = %d start_after->value_pos = %d bytes_before_start_after = %d start_after_new_len = %d bytes_written_after_start_after = %d\n",

2591  fixup.new_len,

2592  reader_array_start_pos,

2593  start_after->value_pos,

2594  bytes_before_start_after,

2595  start_after_new_len,

2596  bytes_written_after_start_after);

2597 #endif

2598  }

2599  }

2600  else

2601  {

2603

2605

2606 #if RECURSIVE_MARSHAL_WRITE_TRACE

2607  _dbus_verbose ("Reading basic value %s at %d\n",

2609  reader->value_pos);

2610 #endif

2611

2613

2614 #if RECURSIVE_MARSHAL_WRITE_TRACE

2615  _dbus_verbose ("Writing basic value %s at %d write target len %d inside_start_after = %d\n",

2617  writer->value_pos,

2618  _dbus_string_get_length (writer->value_str),

2619  inside_start_after);

2620 #endif

2621  if (!inside_start_after)

2622  enable_if_after (writer, reader, start_after);

2623  if (!_dbus_type_writer_write_basic (writer, current_type, &val))

2624  goto oom;

2625 #if RECURSIVE_MARSHAL_WRITE_TRACE

2626  _dbus_verbose ("Wrote basic value %s, new value_pos %d write target len %d\n",

2628  writer->value_pos,

2629  _dbus_string_get_length (writer->value_str));

2630 #endif

2631  }

2632

2634  }

2635

2636  return TRUE;

2637

2638  oom:

2639  if (fixups)

2640  apply_and_free_fixups (fixups, NULL); /* NULL for reader to apply to */

2641

2642  return FALSE;

2643 }

2644

2645 /*

2646 * Iterate through all values in the given reader, writing a copy of

2647 * each value to the writer. The reader will be moved forward to its

2648 * end position.

2649 *

2650 * If a reader start_after is provided, it should be a reader for the

2651 * same data as the reader to be written. Only values occurring after

2652 * the value pointed to by start_after will be written to the writer.

2653 *

2654 * If start_after is provided, then the copy of the reader will be

2655 * partial. This means that array lengths will not have been copied.

2656 * The assumption is that you wrote a new version of the value at

2657 * start_after to the writer. You have to pass in the start position

2658 * and length of the new value. (If you are deleting the value

2659 * at start_after, pass in 0 for the length.)

2660 *

2661 * If the fixups parameter is non-#NULL, then any array length that

2662 * was read but not written due to start_after will be provided

2663 * as a #DBusArrayLenFixup. The fixup contains the position of the

2664 * array length in the source data, and the correct array length

2665 * assuming you combine the source data before start_after with

2666 * the written data at start_after and beyond.

2667 *

2668 * @param writer the writer to copy to

2669 * @param reader the reader to copy from

2670 * @param start_after #NULL or a reader showing where to start

2671 * @param start_after_new_pos the position of start_after equivalent in the target data

2672 * @param start_after_new_len the length of start_after equivalent in the target data

2673 * @param fixups list to append #DBusArrayLenFixup if the write was partial

2674 * @returns #FALSE if no memory

2675 */

2677 _dbus_type_writer_write_reader_partial (DBusTypeWriter *writer,

2679  const DBusTypeReader *start_after,

2680  int start_after_new_pos,

2681  int start_after_new_len,

2682  DBusList **fixups)

2683 {

2685  int orig_type_len;

2686  int orig_value_len;

2687  int new_bytes;

2688  int orig_enabled;

2689

2690  orig = *writer;

2691  orig_type_len = _dbus_string_get_length (writer->type_str);

2692  orig_value_len = _dbus_string_get_length (writer->value_str);

2693  orig_enabled = writer->enabled;

2694

2695  if (start_after)

2696  _dbus_type_writer_set_enabled (writer, FALSE);

2697

2698  if (!writer_write_reader_helper (writer, reader, start_after,

2699  start_after_new_pos,

2700  start_after_new_len,

2701  fixups, FALSE))

2702  goto oom;

2703

2704  _dbus_type_writer_set_enabled (writer, orig_enabled);

2705  return TRUE;

2706

2707  oom:

2709  {

2710  new_bytes = _dbus_string_get_length (writer->type_str) - orig_type_len;

2712  }

2713  new_bytes = _dbus_string_get_length (writer->value_str) - orig_value_len;

2715

2716  *writer = orig;

2717

2718  return FALSE;

2719 }

2720

2733 {

2734  return _dbus_type_writer_write_reader_partial (writer, reader, NULL, 0, 0, NULL);

2735 }

2736

2737 /*

2738 * If disabled, a writer can still be iterated forward and recursed/unrecursed

2739 * but won't write any values. Types will still be written unless the

2740 * writer is a "values only" writer, because the writer needs access to

2741 * a valid signature to be able to iterate.

2742 *

2743 * @param writer the type writer

2744 * @param enabled #TRUE if values should be written

2745 */

2746 static void

2747 _dbus_type_writer_set_enabled (DBusTypeWriter *writer,

2748  dbus_bool_t enabled)

2749 {

2750  writer->enabled = enabled != FALSE;

2751 }

2752  /* end of DBusMarshal group */

2754

2755 /* tests in dbus-marshal-recursive-util.c */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值