You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
3.6 KiB
117 lines
3.6 KiB
#
|
|
# Copyright (C) 2016 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
"""Generic parser class for reading GCNO and GCDA files.
|
|
|
|
Implements read functions for strings, 32-bit integers, and
|
|
64-bit integers.
|
|
"""
|
|
|
|
import struct
|
|
|
|
|
|
class FileFormatError(Exception):
|
|
"""Exception for invalid file format.
|
|
|
|
Thrown when an unexpected value type is read from the file stream
|
|
or when the end of file is reached unexpectedly."""
|
|
|
|
pass
|
|
|
|
|
|
class GcovStreamParserUtil(object):
|
|
"""Parser object for storing the stream and format information.
|
|
|
|
Attributes:
|
|
stream: File stream object for a GCNO file
|
|
format: Character denoting the endianness of the file
|
|
checksum: The checksum (int) of the file
|
|
"""
|
|
|
|
def __init__(self, stream, magic):
|
|
"""Inits the parser with the input stream.
|
|
|
|
The byte order is set by default to little endian and the summary file
|
|
is instantiated with an empty GCNOSummary object.
|
|
|
|
Args:
|
|
stream: An input binary file stream to a .gcno file
|
|
gcno_summary: The summary from a parsed gcno file
|
|
"""
|
|
self.stream = stream
|
|
self.format = '<'
|
|
|
|
tag = self.ReadInt()
|
|
self.version = ''.join(
|
|
struct.unpack(self.format + 'ssss', self.stream.read(4)))
|
|
self.checksum = self.ReadInt()
|
|
|
|
if tag != magic:
|
|
tag = struct.unpack('>I', struct.pack('<I', tag))[0]
|
|
if tag == magic: # switch endianness
|
|
self.format = '>'
|
|
else:
|
|
raise FileFormatError('Invalid file format.')
|
|
|
|
def ReadInt(self):
|
|
"""Reads and returns an integer from the stream.
|
|
|
|
Returns:
|
|
A 4-byte integer from the stream attribute.
|
|
|
|
Raises:
|
|
FileFormatError: Corrupt file.
|
|
"""
|
|
try:
|
|
return struct.unpack(self.format + 'I', self.stream.read(4))[0]
|
|
except (TypeError, ValueError, struct.error) as error:
|
|
raise FileFormatError('Corrupt file.')
|
|
|
|
def ReadInt64(self):
|
|
"""Reads and returns a 64-bit integer from the stream.
|
|
|
|
Returns:
|
|
An 8-byte integer from the stream attribute.
|
|
|
|
Raises:
|
|
FileFormatError: Corrupt file.
|
|
"""
|
|
lo = self.ReadInt()
|
|
hi = self.ReadInt()
|
|
return (hi << 32) | lo
|
|
|
|
def ReadString(self):
|
|
"""Reads and returns a string from the stream.
|
|
|
|
First reads an integer denoting the number of words to read,
|
|
then reads and returns the string with trailing padding characters
|
|
stripped.
|
|
|
|
Returns:
|
|
A string from the stream attribute.
|
|
|
|
Raises:
|
|
FileFormatError: End of file reached.
|
|
"""
|
|
length = self.ReadInt() << 2
|
|
if length > 0:
|
|
try:
|
|
return ''.join(
|
|
struct.unpack(self.format + 's' * length, self.stream.read(
|
|
length))).rstrip('\x00')
|
|
except (TypeError, ValueError, struct.error):
|
|
raise FileFormatError('Corrupt file.')
|
|
return str()
|