19397Sandreas.hansson@arm.com/*
29397Sandreas.hansson@arm.com * Copyright (c) 2012 ARM Limited
39397Sandreas.hansson@arm.com * All rights reserved
49397Sandreas.hansson@arm.com *
59397Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
69397Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
79397Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
89397Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
99397Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
109397Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
119397Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
129397Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
139397Sandreas.hansson@arm.com *
149397Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
159397Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
169397Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
179397Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
189397Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
199397Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
209397Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
219397Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
229397Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
239397Sandreas.hansson@arm.com * this software without specific prior written permission.
249397Sandreas.hansson@arm.com *
259397Sandreas.hansson@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
269397Sandreas.hansson@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
279397Sandreas.hansson@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
289397Sandreas.hansson@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
299397Sandreas.hansson@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
309397Sandreas.hansson@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
319397Sandreas.hansson@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
329397Sandreas.hansson@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
339397Sandreas.hansson@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
349397Sandreas.hansson@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
359397Sandreas.hansson@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
369397Sandreas.hansson@arm.com *
379397Sandreas.hansson@arm.com * Authors: Andreas Hansson
389397Sandreas.hansson@arm.com */
399397Sandreas.hansson@arm.com
4011793Sbrandon.potter@amd.com#include "proto/protoio.hh"
4111793Sbrandon.potter@amd.com
4212334Sgabeblack@google.com#include "base/logging.hh"
439397Sandreas.hansson@arm.com
449397Sandreas.hansson@arm.comusing namespace std;
459397Sandreas.hansson@arm.comusing namespace google::protobuf;
469397Sandreas.hansson@arm.com
479397Sandreas.hansson@arm.comProtoOutputStream::ProtoOutputStream(const string& filename) :
489397Sandreas.hansson@arm.com    fileStream(filename.c_str(), ios::out | ios::binary | ios::trunc),
499705Sandreas.hansson@arm.com    wrappedFileStream(NULL), gzipStream(NULL), zeroCopyStream(NULL)
509397Sandreas.hansson@arm.com{
519397Sandreas.hansson@arm.com    if (!fileStream.good())
529397Sandreas.hansson@arm.com        panic("Could not open %s for writing\n", filename);
539397Sandreas.hansson@arm.com
549397Sandreas.hansson@arm.com    // Wrap the output file in a zero copy stream, that in turn is
559397Sandreas.hansson@arm.com    // wrapped in a gzip stream if the filename ends with .gz. The
569397Sandreas.hansson@arm.com    // latter stream is in turn wrapped in a coded stream
579705Sandreas.hansson@arm.com    wrappedFileStream = new io::OstreamOutputStream(&fileStream);
589397Sandreas.hansson@arm.com    if (filename.find_last_of('.') != string::npos &&
599397Sandreas.hansson@arm.com        filename.substr(filename.find_last_of('.') + 1) == "gz") {
609705Sandreas.hansson@arm.com        gzipStream = new io::GzipOutputStream(wrappedFileStream);
619705Sandreas.hansson@arm.com        zeroCopyStream = gzipStream;
629397Sandreas.hansson@arm.com    } else {
639705Sandreas.hansson@arm.com        zeroCopyStream = wrappedFileStream;
649397Sandreas.hansson@arm.com    }
659397Sandreas.hansson@arm.com
669399Sandreas.hansson@arm.com    // Write the magic number to the file
679705Sandreas.hansson@arm.com    io::CodedOutputStream codedStream(zeroCopyStream);
689705Sandreas.hansson@arm.com    codedStream.WriteLittleEndian32(magicNumber);
699397Sandreas.hansson@arm.com
709397Sandreas.hansson@arm.com    // Note that each type of stream (packet, instruction etc) should
719397Sandreas.hansson@arm.com    // add its own header and perform the appropriate checks
729397Sandreas.hansson@arm.com}
739397Sandreas.hansson@arm.com
749397Sandreas.hansson@arm.comProtoOutputStream::~ProtoOutputStream()
759397Sandreas.hansson@arm.com{
769397Sandreas.hansson@arm.com    // As the compression is optional, see if the stream exists
779397Sandreas.hansson@arm.com    if (gzipStream != NULL)
789397Sandreas.hansson@arm.com        delete gzipStream;
799705Sandreas.hansson@arm.com    delete wrappedFileStream;
809397Sandreas.hansson@arm.com    fileStream.close();
819397Sandreas.hansson@arm.com}
829397Sandreas.hansson@arm.com
839397Sandreas.hansson@arm.comvoid
849397Sandreas.hansson@arm.comProtoOutputStream::write(const Message& msg)
859397Sandreas.hansson@arm.com{
869705Sandreas.hansson@arm.com    // Due to the byte limit of the coded stream we create it for
879705Sandreas.hansson@arm.com    // every single mesage (based on forum discussions around the size
889705Sandreas.hansson@arm.com    // limitation)
899705Sandreas.hansson@arm.com    io::CodedOutputStream codedStream(zeroCopyStream);
909705Sandreas.hansson@arm.com
919397Sandreas.hansson@arm.com    // Write the size of the message to the stream
929705Sandreas.hansson@arm.com    codedStream.WriteVarint32(msg.ByteSize());
939397Sandreas.hansson@arm.com
949397Sandreas.hansson@arm.com    // Write the message itself to the stream
959705Sandreas.hansson@arm.com    msg.SerializeWithCachedSizes(&codedStream);
969397Sandreas.hansson@arm.com}
979399Sandreas.hansson@arm.com
989399Sandreas.hansson@arm.comProtoInputStream::ProtoInputStream(const string& filename) :
999464Sandreas.hansson@arm.com    fileStream(filename.c_str(), ios::in | ios::binary), fileName(filename),
1009399Sandreas.hansson@arm.com    useGzip(false),
1019705Sandreas.hansson@arm.com    wrappedFileStream(NULL), gzipStream(NULL), zeroCopyStream(NULL)
1029399Sandreas.hansson@arm.com{
1039399Sandreas.hansson@arm.com    if (!fileStream.good())
1049399Sandreas.hansson@arm.com        panic("Could not open %s for reading\n", filename);
1059399Sandreas.hansson@arm.com
1069399Sandreas.hansson@arm.com    // check the magic number to see if this is a gzip stream
1079399Sandreas.hansson@arm.com    unsigned char bytes[2];
1089399Sandreas.hansson@arm.com    fileStream.read((char*) bytes, 2);
1099399Sandreas.hansson@arm.com    useGzip = fileStream.good() && bytes[0] == 0x1f && bytes[1] == 0x8b;
1109399Sandreas.hansson@arm.com
1119399Sandreas.hansson@arm.com    // seek to the start of the input file and clear any flags
1129399Sandreas.hansson@arm.com    fileStream.clear();
1139399Sandreas.hansson@arm.com    fileStream.seekg(0, ifstream::beg);
1149399Sandreas.hansson@arm.com
1159399Sandreas.hansson@arm.com    createStreams();
1169399Sandreas.hansson@arm.com}
1179399Sandreas.hansson@arm.com
1189399Sandreas.hansson@arm.comvoid
1199399Sandreas.hansson@arm.comProtoInputStream::createStreams()
1209399Sandreas.hansson@arm.com{
1219399Sandreas.hansson@arm.com    // All streams should be NULL at this point
1229705Sandreas.hansson@arm.com    assert(wrappedFileStream == NULL && gzipStream == NULL &&
1239705Sandreas.hansson@arm.com           zeroCopyStream == NULL);
1249399Sandreas.hansson@arm.com
1259399Sandreas.hansson@arm.com    // Wrap the input file in a zero copy stream, that in turn is
1269399Sandreas.hansson@arm.com    // wrapped in a gzip stream if the filename ends with .gz. The
1279399Sandreas.hansson@arm.com    // latter stream is in turn wrapped in a coded stream
1289705Sandreas.hansson@arm.com    wrappedFileStream = new io::IstreamInputStream(&fileStream);
1299399Sandreas.hansson@arm.com    if (useGzip) {
1309705Sandreas.hansson@arm.com        gzipStream = new io::GzipInputStream(wrappedFileStream);
1319705Sandreas.hansson@arm.com        zeroCopyStream = gzipStream;
1329399Sandreas.hansson@arm.com    } else {
1339705Sandreas.hansson@arm.com        zeroCopyStream = wrappedFileStream;
1349399Sandreas.hansson@arm.com    }
1359399Sandreas.hansson@arm.com
1369399Sandreas.hansson@arm.com    uint32_t magic_check;
1379705Sandreas.hansson@arm.com    io::CodedInputStream codedStream(zeroCopyStream);
1389705Sandreas.hansson@arm.com    if (!codedStream.ReadLittleEndian32(&magic_check) ||
1399399Sandreas.hansson@arm.com        magic_check != magicNumber)
1409399Sandreas.hansson@arm.com        panic("Input file %s is not a valid gem5 proto format.\n",
1419399Sandreas.hansson@arm.com              fileName);
1429399Sandreas.hansson@arm.com}
1439399Sandreas.hansson@arm.com
1449399Sandreas.hansson@arm.comvoid
1459399Sandreas.hansson@arm.comProtoInputStream::destroyStreams()
1469399Sandreas.hansson@arm.com{
1479399Sandreas.hansson@arm.com    // As the compression is optional, see if the stream exists
1489399Sandreas.hansson@arm.com    if (gzipStream != NULL) {
1499399Sandreas.hansson@arm.com        delete gzipStream;
1509399Sandreas.hansson@arm.com        gzipStream = NULL;
1519399Sandreas.hansson@arm.com    }
1529705Sandreas.hansson@arm.com    delete wrappedFileStream;
1539705Sandreas.hansson@arm.com    wrappedFileStream = NULL;
1549705Sandreas.hansson@arm.com
1559399Sandreas.hansson@arm.com    zeroCopyStream = NULL;
1569399Sandreas.hansson@arm.com}
1579399Sandreas.hansson@arm.com
1589399Sandreas.hansson@arm.com
1599399Sandreas.hansson@arm.comProtoInputStream::~ProtoInputStream()
1609399Sandreas.hansson@arm.com{
1619399Sandreas.hansson@arm.com    destroyStreams();
1629399Sandreas.hansson@arm.com    fileStream.close();
1639399Sandreas.hansson@arm.com}
1649399Sandreas.hansson@arm.com
1659399Sandreas.hansson@arm.com
1669399Sandreas.hansson@arm.comvoid
1679399Sandreas.hansson@arm.comProtoInputStream::reset()
1689399Sandreas.hansson@arm.com{
1699399Sandreas.hansson@arm.com    destroyStreams();
1709399Sandreas.hansson@arm.com    // seek to the start of the input file and clear any flags
1719399Sandreas.hansson@arm.com    fileStream.clear();
1729399Sandreas.hansson@arm.com    fileStream.seekg(0, ifstream::beg);
1739399Sandreas.hansson@arm.com    createStreams();
1749399Sandreas.hansson@arm.com}
1759399Sandreas.hansson@arm.com
1769399Sandreas.hansson@arm.combool
1779399Sandreas.hansson@arm.comProtoInputStream::read(Message& msg)
1789399Sandreas.hansson@arm.com{
1799399Sandreas.hansson@arm.com    // Read a message from the stream by getting the size, using it as
1809399Sandreas.hansson@arm.com    // a limit when parsing the message, then popping the limit again
1819399Sandreas.hansson@arm.com    uint32_t size;
1829705Sandreas.hansson@arm.com
1839705Sandreas.hansson@arm.com    // Due to the byte limit of the coded stream we create it for
1849705Sandreas.hansson@arm.com    // every single mesage (based on forum discussions around the size
1859705Sandreas.hansson@arm.com    // limitation)
1869705Sandreas.hansson@arm.com    io::CodedInputStream codedStream(zeroCopyStream);
1879705Sandreas.hansson@arm.com    if (codedStream.ReadVarint32(&size)) {
1889705Sandreas.hansson@arm.com        io::CodedInputStream::Limit limit = codedStream.PushLimit(size);
1899705Sandreas.hansson@arm.com        if (msg.ParseFromCodedStream(&codedStream)) {
1909705Sandreas.hansson@arm.com            codedStream.PopLimit(limit);
1919399Sandreas.hansson@arm.com            // All went well, the message is parsed and the limit is
1929399Sandreas.hansson@arm.com            // popped again
1939399Sandreas.hansson@arm.com            return true;
1949399Sandreas.hansson@arm.com        } else {
1959399Sandreas.hansson@arm.com            panic("Unable to read message from coded stream %s\n",
1969399Sandreas.hansson@arm.com                  fileName);
1979399Sandreas.hansson@arm.com        }
1989399Sandreas.hansson@arm.com    }
1999399Sandreas.hansson@arm.com
2009399Sandreas.hansson@arm.com    return false;
2019399Sandreas.hansson@arm.com}
202