/**
  * Parses protobuf file and returns MessageDescriptor
  *
  * @param FileDescriptor    $file           File descriptors
  * @param string            $messageContent Protobuf message content
  * @param MessageDescriptor $parent         Parent message (if nested)
  *
  * @return MessageDescriptor
  *
  * @throws Exception
  */
 private function _parseMessageType(FileDescriptor $file, $messageContent, MessageDescriptor $parent = null)
 {
     if ($messageContent == '') {
         return;
     }
     while (strlen($messageContent) > 0) {
         $next = $this->_next($messageContent);
         if (strtolower($next) == 'message') {
             $messageContent = trim(substr($messageContent, strlen($next)));
             $name = $this->_next($messageContent);
             $offset = $this->_getBeginEnd($messageContent, '{', '}');
             // now extract the content and call parse_message again
             $content = trim(substr($messageContent, $offset['begin'] + 1, $offset['end'] - $offset['begin'] - 2));
             $childMessage = new MessageDescriptor($name, $file, $parent);
             $this->_parseMessageType($file, $content, $childMessage);
             $messageContent = '' . trim(substr($messageContent, $offset['end']));
         } else {
             if (strtolower($next) == 'enum') {
                 $messageContent = trim(substr($messageContent, strlen($next)));
                 $name = $this->_next($messageContent);
                 $offset = $this->_getBeginEnd($messageContent, '{', '}');
                 // now extract the content and call parse_message again
                 $content = trim(substr($messageContent, $offset['begin'] + 1, $offset['end'] - $offset['begin'] - 2));
                 $enum = new EnumDescriptor($name, $file, $parent);
                 $this->_parseEnum($enum, $content);
                 // removing it from string
                 $messageContent = '' . trim(substr($messageContent, $offset['end']));
             } else {
                 if (strtolower($next) == 'import') {
                     $name = $this->_next($messageContent);
                     $match = preg_match('/"([^"]+)";*\\s?/', $messageContent, $matches, PREG_OFFSET_CAPTURE);
                     if (!$match) {
                         throw new Exception('Malformed include / look at your import statement: ' . $messageContent);
                     }
                     $includedFilename = $matches[1][0];
                     if (!file_exists($includedFilename)) {
                         throw new Exception('Included file ' . $includedFilename . ' does not exist');
                     }
                     $messageContent = trim(substr($messageContent, $matches[0][1] + strlen($matches[0][0])));
                     $parserKey = realpath($includedFilename);
                     if (!isset(self::$_parsers[$parserKey])) {
                         $pbp = new ProtobufParser($this->_useNativeNamespaces);
                         self::$_parsers[$parserKey] = $pbp;
                     } else {
                         $pbp = self::$_parsers[$parserKey];
                     }
                     $file->addDependency($pbp->parse($includedFilename));
                 } else {
                     if (strtolower($next) == 'option') {
                         // We don't support option parameters just yet, skip for now.
                         $messageContent = preg_replace('/^.+\\n/', '', $messageContent);
                     } else {
                         if (strtolower($next) == 'package') {
                             $match = preg_match('/package[\\s]+([^;]+);?/', $messageContent, $matches, PREG_OFFSET_CAPTURE);
                             if (!$match) {
                                 throw new Exception('Malformed package');
                             }
                             $file->setPackage($matches[1][0]);
                             $messageContent = trim(substr($messageContent, $matches[0][1] + strlen($matches[0][0])));
                         } else {
                             // now a normal field
                             $match = preg_match('/(.*);/', $messageContent, $matches, PREG_OFFSET_CAPTURE);
                             if (!$match || !$parent) {
                                 throw new Exception('Proto file missformed');
                             }
                             $parent->addField($this->_parseField($matches[0][0]));
                             $messageContent = trim(substr($messageContent, $matches[0][1] + strlen($matches[0][0])));
                         }
                     }
                 }
             }
         }
     }
 }