OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 643 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
654 Pattern.CASE_INSENSITIVE); | 654 Pattern.CASE_INSENSITIVE); |
655 | 655 |
656 /** Construct a tokenizer that parses tokens from the given text. */ | 656 /** Construct a tokenizer that parses tokens from the given text. */ |
657 private Tokenizer(final CharSequence text) { | 657 private Tokenizer(final CharSequence text) { |
658 this.text = text; | 658 this.text = text; |
659 this.matcher = WHITESPACE.matcher(text); | 659 this.matcher = WHITESPACE.matcher(text); |
660 skipWhitespace(); | 660 skipWhitespace(); |
661 nextToken(); | 661 nextToken(); |
662 } | 662 } |
663 | 663 |
| 664 int getPreviousLine() { |
| 665 return previousLine; |
| 666 } |
| 667 |
| 668 int getPreviousColumn() { |
| 669 return previousColumn; |
| 670 } |
| 671 |
664 int getLine() { | 672 int getLine() { |
665 return line; | 673 return line; |
666 } | 674 } |
667 | 675 |
668 int getColumn() { | 676 int getColumn() { |
669 return column; | 677 return column; |
670 } | 678 } |
671 | 679 |
672 /** Are we at the end of the input? */ | 680 /** Are we at the end of the input? */ |
673 public boolean atEnd() { | 681 public boolean atEnd() { |
(...skipping 693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1367 final int n = input.read(buffer); | 1375 final int n = input.read(buffer); |
1368 if (n == -1) { | 1376 if (n == -1) { |
1369 break; | 1377 break; |
1370 } | 1378 } |
1371 buffer.flip(); | 1379 buffer.flip(); |
1372 text.append(buffer, 0, n); | 1380 text.append(buffer, 0, n); |
1373 } | 1381 } |
1374 return text; | 1382 return text; |
1375 } | 1383 } |
1376 | 1384 |
| 1385 // Check both unknown fields and unknown extensions and log warming messages |
| 1386 // or throw exceptions according to the flag. |
| 1387 private void checkUnknownFields(final List<String> unknownFields) |
| 1388 throws ParseException { |
| 1389 if (unknownFields.isEmpty()) { |
| 1390 return; |
| 1391 } |
| 1392 |
| 1393 StringBuilder msg = new StringBuilder("Input contains unknown fields and/o
r extensions:"); |
| 1394 for (String field : unknownFields) { |
| 1395 msg.append('\n').append(field); |
| 1396 } |
| 1397 |
| 1398 if (allowUnknownFields) { |
| 1399 logger.warning(msg.toString()); |
| 1400 } else { |
| 1401 String[] lineColumn = unknownFields.get(0).split(":"); |
| 1402 throw new ParseException(Integer.valueOf(lineColumn[0]), |
| 1403 Integer.valueOf(lineColumn[1]), msg.toString()); |
| 1404 } |
| 1405 } |
| 1406 |
1377 /** | 1407 /** |
1378 * Parse a text-format message from {@code input} and merge the contents | 1408 * Parse a text-format message from {@code input} and merge the contents |
1379 * into {@code builder}. Extensions will be recognized if they are | 1409 * into {@code builder}. Extensions will be recognized if they are |
1380 * registered in {@code extensionRegistry}. | 1410 * registered in {@code extensionRegistry}. |
1381 */ | 1411 */ |
1382 public void merge(final CharSequence input, | 1412 public void merge(final CharSequence input, |
1383 final ExtensionRegistry extensionRegistry, | 1413 final ExtensionRegistry extensionRegistry, |
1384 final Message.Builder builder) | 1414 final Message.Builder builder) |
1385 throws ParseException { | 1415 throws ParseException { |
1386 final Tokenizer tokenizer = new Tokenizer(input); | 1416 final Tokenizer tokenizer = new Tokenizer(input); |
1387 MessageReflection.BuilderAdapter target = | 1417 MessageReflection.BuilderAdapter target = |
1388 new MessageReflection.BuilderAdapter(builder); | 1418 new MessageReflection.BuilderAdapter(builder); |
1389 | 1419 |
| 1420 List<String> unknownFields = new ArrayList<String>(); |
| 1421 |
1390 while (!tokenizer.atEnd()) { | 1422 while (!tokenizer.atEnd()) { |
1391 mergeField(tokenizer, extensionRegistry, target); | 1423 mergeField(tokenizer, extensionRegistry, target, unknownFields); |
1392 } | 1424 } |
| 1425 |
| 1426 checkUnknownFields(unknownFields); |
1393 } | 1427 } |
1394 | 1428 |
1395 | 1429 |
1396 /** | 1430 /** |
1397 * Parse a single field from {@code tokenizer} and merge it into | 1431 * Parse a single field from {@code tokenizer} and merge it into |
1398 * {@code builder}. | 1432 * {@code builder}. |
1399 */ | 1433 */ |
1400 private void mergeField(final Tokenizer tokenizer, | 1434 private void mergeField(final Tokenizer tokenizer, |
1401 final ExtensionRegistry extensionRegistry, | 1435 final ExtensionRegistry extensionRegistry, |
1402 final MessageReflection.MergeTarget target) | 1436 final MessageReflection.MergeTarget target, |
| 1437 List<String> unknownFields) |
1403 throws ParseException { | 1438 throws ParseException { |
1404 mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder); | 1439 mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder, |
| 1440 unknownFields); |
1405 } | 1441 } |
1406 | 1442 |
1407 /** | 1443 /** |
1408 * Parse a single field from {@code tokenizer} and merge it into | 1444 * Parse a single field from {@code tokenizer} and merge it into |
1409 * {@code builder}. | 1445 * {@code builder}. |
1410 */ | 1446 */ |
1411 private void mergeField(final Tokenizer tokenizer, | 1447 private void mergeField(final Tokenizer tokenizer, |
1412 final ExtensionRegistry extensionRegistry, | 1448 final ExtensionRegistry extensionRegistry, |
1413 final MessageReflection.MergeTarget target, | 1449 final MessageReflection.MergeTarget target, |
1414 TextFormatParseInfoTree.Builder parseTreeBuilder) | 1450 TextFormatParseInfoTree.Builder parseTreeBuilder, |
| 1451 List<String> unknownFields) |
1415 throws ParseException { | 1452 throws ParseException { |
1416 FieldDescriptor field = null; | 1453 FieldDescriptor field = null; |
1417 int startLine = tokenizer.getLine(); | 1454 int startLine = tokenizer.getLine(); |
1418 int startColumn = tokenizer.getColumn(); | 1455 int startColumn = tokenizer.getColumn(); |
1419 final Descriptor type = target.getDescriptorForType(); | 1456 final Descriptor type = target.getDescriptorForType(); |
1420 ExtensionRegistry.ExtensionInfo extension = null; | 1457 ExtensionRegistry.ExtensionInfo extension = null; |
1421 | 1458 |
1422 if (tokenizer.tryConsume("[")) { | 1459 if (tokenizer.tryConsume("[")) { |
1423 // An extension. | 1460 // An extension. |
1424 final StringBuilder name = | 1461 final StringBuilder name = |
1425 new StringBuilder(tokenizer.consumeIdentifier()); | 1462 new StringBuilder(tokenizer.consumeIdentifier()); |
1426 while (tokenizer.tryConsume(".")) { | 1463 while (tokenizer.tryConsume(".")) { |
1427 name.append('.'); | 1464 name.append('.'); |
1428 name.append(tokenizer.consumeIdentifier()); | 1465 name.append(tokenizer.consumeIdentifier()); |
1429 } | 1466 } |
1430 | 1467 |
1431 extension = target.findExtensionByName( | 1468 extension = target.findExtensionByName( |
1432 extensionRegistry, name.toString()); | 1469 extensionRegistry, name.toString()); |
1433 | 1470 |
1434 if (extension == null) { | 1471 if (extension == null) { |
1435 if (!allowUnknownFields) { | 1472 unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" + |
1436 throw tokenizer.parseExceptionPreviousToken( | 1473 (tokenizer.getPreviousColumn() + 1) + ":\t" + |
1437 "Extension \"" + name + "\" not found in the ExtensionRegistry."); | 1474 type.getFullName() + ".[" + name + "]"); |
1438 } else { | |
1439 logger.warning( | |
1440 "Extension \"" + name + "\" not found in the ExtensionRegistry."); | |
1441 } | |
1442 } else { | 1475 } else { |
1443 if (extension.descriptor.getContainingType() != type) { | 1476 if (extension.descriptor.getContainingType() != type) { |
1444 throw tokenizer.parseExceptionPreviousToken( | 1477 throw tokenizer.parseExceptionPreviousToken( |
1445 "Extension \"" + name + "\" does not extend message type \"" | 1478 "Extension \"" + name + "\" does not extend message type \"" |
1446 + type.getFullName() + "\"."); | 1479 + type.getFullName() + "\"."); |
1447 } | 1480 } |
1448 field = extension.descriptor; | 1481 field = extension.descriptor; |
1449 } | 1482 } |
1450 | 1483 |
1451 tokenizer.consume("]"); | 1484 tokenizer.consume("]"); |
(...skipping 14 matching lines...) Expand all Loading... |
1466 field = null; | 1499 field = null; |
1467 } | 1500 } |
1468 } | 1501 } |
1469 // Again, special-case group names as described above. | 1502 // Again, special-case group names as described above. |
1470 if (field != null && field.getType() == FieldDescriptor.Type.GROUP | 1503 if (field != null && field.getType() == FieldDescriptor.Type.GROUP |
1471 && !field.getMessageType().getName().equals(name)) { | 1504 && !field.getMessageType().getName().equals(name)) { |
1472 field = null; | 1505 field = null; |
1473 } | 1506 } |
1474 | 1507 |
1475 if (field == null) { | 1508 if (field == null) { |
1476 if (!allowUnknownFields) { | 1509 unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" + |
1477 throw tokenizer.unknownFieldParseExceptionPreviousToken( | 1510 (tokenizer.getPreviousColumn() + 1) + ":\t" + |
1478 name, | 1511 type.getFullName() + "." + name); |
1479 "Message type \"" + type.getFullName() | |
1480 + "\" has no field named \"" + name + "\"."); | |
1481 } else { | |
1482 logger.warning( | |
1483 "Message type \"" + type.getFullName() | |
1484 + "\" has no field named \"" + name + "\"."); | |
1485 } | |
1486 } | 1512 } |
1487 } | 1513 } |
1488 | 1514 |
1489 // Skips unknown fields. | 1515 // Skips unknown fields. |
1490 if (field == null) { | 1516 if (field == null) { |
1491 // Try to guess the type of this field. | 1517 // Try to guess the type of this field. |
1492 // If this field is not a message, there should be a ":" between the | 1518 // If this field is not a message, there should be a ":" between the |
1493 // field name and the field value and also the field value should not | 1519 // field name and the field value and also the field value should not |
1494 // start with "{" or "<" which indicates the beginning of a message body
. | 1520 // start with "{" or "<" which indicates the beginning of a message body
. |
1495 // If there is no ":" or there is a "{" or "<" after ":", this field has | 1521 // If there is no ":" or there is a "{" or "<" after ":", this field has |
1496 // to be a message or the input is ill-formed. | 1522 // to be a message or the input is ill-formed. |
1497 if (tokenizer.tryConsume(":") | 1523 if (tokenizer.tryConsume(":") |
1498 && !tokenizer.lookingAt("{") | 1524 && !tokenizer.lookingAt("{") |
1499 && !tokenizer.lookingAt("<")) { | 1525 && !tokenizer.lookingAt("<")) { |
1500 skipFieldValue(tokenizer); | 1526 skipFieldValue(tokenizer); |
1501 } else { | 1527 } else { |
1502 skipFieldMessage(tokenizer); | 1528 skipFieldMessage(tokenizer); |
1503 } | 1529 } |
1504 return; | 1530 return; |
1505 } | 1531 } |
1506 | 1532 |
1507 // Handle potential ':'. | 1533 // Handle potential ':'. |
1508 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { | 1534 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { |
1509 tokenizer.tryConsume(":"); // optional | 1535 tokenizer.tryConsume(":"); // optional |
1510 if (parseTreeBuilder != null) { | 1536 if (parseTreeBuilder != null) { |
1511 TextFormatParseInfoTree.Builder childParseTreeBuilder = | 1537 TextFormatParseInfoTree.Builder childParseTreeBuilder = |
1512 parseTreeBuilder.getBuilderForSubMessageField(field); | 1538 parseTreeBuilder.getBuilderForSubMessageField(field); |
1513 consumeFieldValues(tokenizer, extensionRegistry, target, field, extens
ion, | 1539 consumeFieldValues(tokenizer, extensionRegistry, target, field, extens
ion, |
1514 childParseTreeBuilder); | 1540 childParseTreeBuilder, unknownFields); |
1515 } else { | 1541 } else { |
1516 consumeFieldValues(tokenizer, extensionRegistry, target, field, extens
ion, | 1542 consumeFieldValues(tokenizer, extensionRegistry, target, field, extens
ion, |
1517 parseTreeBuilder); | 1543 parseTreeBuilder, unknownFields); |
1518 } | 1544 } |
1519 } else { | 1545 } else { |
1520 tokenizer.consume(":"); // required | 1546 tokenizer.consume(":"); // required |
1521 consumeFieldValues( | 1547 consumeFieldValues(tokenizer, extensionRegistry, target, field, |
1522 tokenizer, extensionRegistry, target, field, extension, parseTreeBui
lder); | 1548 extension, parseTreeBuilder, unknownFields); |
1523 } | 1549 } |
1524 | 1550 |
1525 if (parseTreeBuilder != null) { | 1551 if (parseTreeBuilder != null) { |
1526 parseTreeBuilder.setLocation( | 1552 parseTreeBuilder.setLocation( |
1527 field, TextFormatParseLocation.create(startLine, startColumn)); | 1553 field, TextFormatParseLocation.create(startLine, startColumn)); |
1528 } | 1554 } |
1529 | 1555 |
1530 // For historical reasons, fields may optionally be separated by commas or | 1556 // For historical reasons, fields may optionally be separated by commas or |
1531 // semicolons. | 1557 // semicolons. |
1532 if (!tokenizer.tryConsume(";")) { | 1558 if (!tokenizer.tryConsume(";")) { |
1533 tokenizer.tryConsume(","); | 1559 tokenizer.tryConsume(","); |
1534 } | 1560 } |
1535 } | 1561 } |
1536 | 1562 |
1537 /** | 1563 /** |
1538 * Parse a one or more field values from {@code tokenizer} and merge it into | 1564 * Parse a one or more field values from {@code tokenizer} and merge it into |
1539 * {@code builder}. | 1565 * {@code builder}. |
1540 */ | 1566 */ |
1541 private void consumeFieldValues( | 1567 private void consumeFieldValues( |
1542 final Tokenizer tokenizer, | 1568 final Tokenizer tokenizer, |
1543 final ExtensionRegistry extensionRegistry, | 1569 final ExtensionRegistry extensionRegistry, |
1544 final MessageReflection.MergeTarget target, | 1570 final MessageReflection.MergeTarget target, |
1545 final FieldDescriptor field, | 1571 final FieldDescriptor field, |
1546 final ExtensionRegistry.ExtensionInfo extension, | 1572 final ExtensionRegistry.ExtensionInfo extension, |
1547 final TextFormatParseInfoTree.Builder parseTreeBuilder) | 1573 final TextFormatParseInfoTree.Builder parseTreeBuilder, |
| 1574 List<String> unknownFields) |
1548 throws ParseException { | 1575 throws ParseException { |
1549 // Support specifying repeated field values as a comma-separated list. | 1576 // Support specifying repeated field values as a comma-separated list. |
1550 // Ex."foo: [1, 2, 3]" | 1577 // Ex."foo: [1, 2, 3]" |
1551 if (field.isRepeated() && tokenizer.tryConsume("[")) { | 1578 if (field.isRepeated() && tokenizer.tryConsume("[")) { |
1552 while (true) { | 1579 if (!tokenizer.tryConsume("]")) { // Allow "foo: []" to be treated as e
mpty. |
1553 consumeFieldValue(tokenizer, extensionRegistry, target, field, extensi
on, | 1580 while (true) { |
1554 parseTreeBuilder); | 1581 consumeFieldValue( |
1555 if (tokenizer.tryConsume("]")) { | 1582 tokenizer, |
1556 // End of list. | 1583 extensionRegistry, |
1557 break; | 1584 target, |
| 1585 field, |
| 1586 extension, |
| 1587 parseTreeBuilder, |
| 1588 unknownFields); |
| 1589 if (tokenizer.tryConsume("]")) { |
| 1590 // End of list. |
| 1591 break; |
| 1592 } |
| 1593 tokenizer.consume(","); |
1558 } | 1594 } |
1559 tokenizer.consume(","); | |
1560 } | 1595 } |
1561 } else { | 1596 } else { |
1562 consumeFieldValue( | 1597 consumeFieldValue(tokenizer, extensionRegistry, target, field, |
1563 tokenizer, extensionRegistry, target, field, extension, parseTreeBui
lder); | 1598 extension, parseTreeBuilder, unknownFields); |
1564 } | 1599 } |
1565 } | 1600 } |
1566 | 1601 |
1567 /** | 1602 /** |
1568 * Parse a single field value from {@code tokenizer} and merge it into | 1603 * Parse a single field value from {@code tokenizer} and merge it into |
1569 * {@code builder}. | 1604 * {@code builder}. |
1570 */ | 1605 */ |
1571 private void consumeFieldValue( | 1606 private void consumeFieldValue( |
1572 final Tokenizer tokenizer, | 1607 final Tokenizer tokenizer, |
1573 final ExtensionRegistry extensionRegistry, | 1608 final ExtensionRegistry extensionRegistry, |
1574 final MessageReflection.MergeTarget target, | 1609 final MessageReflection.MergeTarget target, |
1575 final FieldDescriptor field, | 1610 final FieldDescriptor field, |
1576 final ExtensionRegistry.ExtensionInfo extension, | 1611 final ExtensionRegistry.ExtensionInfo extension, |
1577 final TextFormatParseInfoTree.Builder parseTreeBuilder) | 1612 final TextFormatParseInfoTree.Builder parseTreeBuilder, |
| 1613 List<String> unknownFields) |
1578 throws ParseException { | 1614 throws ParseException { |
1579 Object value = null; | 1615 Object value = null; |
1580 | 1616 |
1581 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { | 1617 if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { |
1582 final String endToken; | 1618 final String endToken; |
1583 if (tokenizer.tryConsume("<")) { | 1619 if (tokenizer.tryConsume("<")) { |
1584 endToken = ">"; | 1620 endToken = ">"; |
1585 } else { | 1621 } else { |
1586 tokenizer.consume("{"); | 1622 tokenizer.consume("{"); |
1587 endToken = "}"; | 1623 endToken = "}"; |
1588 } | 1624 } |
1589 | 1625 |
1590 final MessageReflection.MergeTarget subField; | 1626 final MessageReflection.MergeTarget subField; |
1591 subField = target.newMergeTargetForField(field, | 1627 subField = target.newMergeTargetForField(field, |
1592 (extension == null) ? null : extension.defaultInstance); | 1628 (extension == null) ? null : extension.defaultInstance); |
1593 | 1629 |
1594 while (!tokenizer.tryConsume(endToken)) { | 1630 while (!tokenizer.tryConsume(endToken)) { |
1595 if (tokenizer.atEnd()) { | 1631 if (tokenizer.atEnd()) { |
1596 throw tokenizer.parseException( | 1632 throw tokenizer.parseException( |
1597 "Expected \"" + endToken + "\"."); | 1633 "Expected \"" + endToken + "\"."); |
1598 } | 1634 } |
1599 mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder); | 1635 mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder, |
| 1636 unknownFields); |
1600 } | 1637 } |
1601 | 1638 |
1602 value = subField.finish(); | 1639 value = subField.finish(); |
1603 | 1640 |
1604 } else { | 1641 } else { |
1605 switch (field.getType()) { | 1642 switch (field.getType()) { |
1606 case INT32: | 1643 case INT32: |
1607 case SINT32: | 1644 case SINT32: |
1608 case SFIXED32: | 1645 case SFIXED32: |
1609 value = tokenizer.consumeInt32(); | 1646 value = tokenizer.consumeInt32(); |
(...skipping 452 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2062 } | 2099 } |
2063 } | 2100 } |
2064 } | 2101 } |
2065 | 2102 |
2066 result = bigValue.longValue(); | 2103 result = bigValue.longValue(); |
2067 } | 2104 } |
2068 | 2105 |
2069 return result; | 2106 return result; |
2070 } | 2107 } |
2071 } | 2108 } |
OLD | NEW |