1# 2# Copyright (C) 2016 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16"""Generic parser class for reading GCNO and GCDA files. 17 18Implements read functions for strings, 32-bit integers, and 1964-bit integers. 20""" 21 22import struct 23 24 25class FileFormatError(Exception): 26 """Exception for invalid file format. 27 28 Thrown when an unexpected value type is read from the file stream 29 or when the end of file is reached unexpectedly.""" 30 31 pass 32 33 34class GcovStreamParserUtil(object): 35 """Parser object for storing the stream and format information. 36 37 Attributes: 38 stream: File stream object for a GCNO file 39 format: Character denoting the endianness of the file 40 checksum: The checksum (int) of the file 41 """ 42 43 def __init__(self, stream, magic): 44 """Inits the parser with the input stream. 45 46 The byte order is set by default to little endian and the summary file 47 is instantiated with an empty GCNOSummary object. 48 49 Args: 50 stream: An input binary file stream to a .gcno file 51 gcno_summary: The summary from a parsed gcno file 52 """ 53 self.stream = stream 54 self.format = '<' 55 56 tag = self.ReadInt() 57 self.version = ''.join( 58 struct.unpack(self.format + 'ssss', self.stream.read(4))) 59 self.checksum = self.ReadInt() 60 61 if tag != magic: 62 tag = struct.unpack('>I', struct.pack('<I', tag))[0] 63 if tag == magic: # switch endianness 64 self.format = '>' 65 else: 66 raise FileFormatError('Invalid file format.') 67 68 def ReadInt(self): 69 """Reads and returns an integer from the stream. 70 71 Returns: 72 A 4-byte integer from the stream attribute. 73 74 Raises: 75 FileFormatError: Corrupt file. 76 """ 77 try: 78 return struct.unpack(self.format + 'I', self.stream.read(4))[0] 79 except (TypeError, ValueError, struct.error) as error: 80 raise FileFormatError('Corrupt file.') 81 82 def ReadInt64(self): 83 """Reads and returns a 64-bit integer from the stream. 84 85 Returns: 86 An 8-byte integer from the stream attribute. 87 88 Raises: 89 FileFormatError: Corrupt file. 90 """ 91 lo = self.ReadInt() 92 hi = self.ReadInt() 93 return (hi << 32) | lo 94 95 def ReadString(self): 96 """Reads and returns a string from the stream. 97 98 First reads an integer denoting the number of words to read, 99 then reads and returns the string with trailing padding characters 100 stripped. 101 102 Returns: 103 A string from the stream attribute. 104 105 Raises: 106 FileFormatError: End of file reached. 107 """ 108 length = self.ReadInt() << 2 109 if length > 0: 110 try: 111 return ''.join( 112 struct.unpack(self.format + 's' * length, self.stream.read( 113 length))).rstrip('\x00') 114 except (TypeError, ValueError, struct.error): 115 raise FileFormatError('Corrupt file.') 116 return str() 117