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