protoio.cc revision 9705
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
409397Sandreas.hansson@arm.com#include "base/misc.hh"
419397Sandreas.hansson@arm.com#include "proto/protoio.hh"
429397Sandreas.hansson@arm.com
439397Sandreas.hansson@arm.comusing namespace std;
449397Sandreas.hansson@arm.comusing namespace google::protobuf;
459397Sandreas.hansson@arm.com
469397Sandreas.hansson@arm.comProtoOutputStream::ProtoOutputStream(const string& filename) :
479397Sandreas.hansson@arm.com    fileStream(filename.c_str(), ios::out | ios::binary | ios::trunc),
489705Sandreas.hansson@arm.com    wrappedFileStream(NULL), gzipStream(NULL), zeroCopyStream(NULL)
499397Sandreas.hansson@arm.com{
509397Sandreas.hansson@arm.com    if (!fileStream.good())
519397Sandreas.hansson@arm.com        panic("Could not open %s for writing\n", filename);
529397Sandreas.hansson@arm.com
539397Sandreas.hansson@arm.com    // Wrap the output file in a zero copy stream, that in turn is
549397Sandreas.hansson@arm.com    // wrapped in a gzip stream if the filename ends with .gz. The
559397Sandreas.hansson@arm.com    // latter stream is in turn wrapped in a coded stream
569705Sandreas.hansson@arm.com    wrappedFileStream = new io::OstreamOutputStream(&fileStream);
579397Sandreas.hansson@arm.com    if (filename.find_last_of('.') != string::npos &&
589397Sandreas.hansson@arm.com        filename.substr(filename.find_last_of('.') + 1) == "gz") {
599705Sandreas.hansson@arm.com        gzipStream = new io::GzipOutputStream(wrappedFileStream);
609705Sandreas.hansson@arm.com        zeroCopyStream = gzipStream;
619397Sandreas.hansson@arm.com    } else {
629705Sandreas.hansson@arm.com        zeroCopyStream = wrappedFileStream;
639397Sandreas.hansson@arm.com    }
649397Sandreas.hansson@arm.com
659399Sandreas.hansson@arm.com    // Write the magic number to the file
669705Sandreas.hansson@arm.com    io::CodedOutputStream codedStream(zeroCopyStream);
679705Sandreas.hansson@arm.com    codedStream.WriteLittleEndian32(magicNumber);
689397Sandreas.hansson@arm.com
699397Sandreas.hansson@arm.com    // Note that each type of stream (packet, instruction etc) should
709397Sandreas.hansson@arm.com    // add its own header and perform the appropriate checks
719397Sandreas.hansson@arm.com}
729397Sandreas.hansson@arm.com
739397Sandreas.hansson@arm.comProtoOutputStream::~ProtoOutputStream()
749397Sandreas.hansson@arm.com{
759397Sandreas.hansson@arm.com    // As the compression is optional, see if the stream exists
769397Sandreas.hansson@arm.com    if (gzipStream != NULL)
779397Sandreas.hansson@arm.com        delete gzipStream;
789705Sandreas.hansson@arm.com    delete wrappedFileStream;
799397Sandreas.hansson@arm.com    fileStream.close();
809397Sandreas.hansson@arm.com}
819397Sandreas.hansson@arm.com
829397Sandreas.hansson@arm.comvoid
839397Sandreas.hansson@arm.comProtoOutputStream::write(const Message& msg)
849397Sandreas.hansson@arm.com{
859705Sandreas.hansson@arm.com    // Due to the byte limit of the coded stream we create it for
869705Sandreas.hansson@arm.com    // every single mesage (based on forum discussions around the size
879705Sandreas.hansson@arm.com    // limitation)
889705Sandreas.hansson@arm.com    io::CodedOutputStream codedStream(zeroCopyStream);
899705Sandreas.hansson@arm.com
909397Sandreas.hansson@arm.com    // Write the size of the message to the stream
919705Sandreas.hansson@arm.com    codedStream.WriteVarint32(msg.ByteSize());
929397Sandreas.hansson@arm.com
939397Sandreas.hansson@arm.com    // Write the message itself to the stream
949705Sandreas.hansson@arm.com    msg.SerializeWithCachedSizes(&codedStream);
959397Sandreas.hansson@arm.com}
969399Sandreas.hansson@arm.com
979399Sandreas.hansson@arm.comProtoInputStream::ProtoInputStream(const string& filename) :
989464Sandreas.hansson@arm.com    fileStream(filename.c_str(), ios::in | ios::binary), fileName(filename),
999399Sandreas.hansson@arm.com    useGzip(false),
1009705Sandreas.hansson@arm.com    wrappedFileStream(NULL), gzipStream(NULL), zeroCopyStream(NULL)
1019399Sandreas.hansson@arm.com{
1029399Sandreas.hansson@arm.com    if (!fileStream.good())
1039399Sandreas.hansson@arm.com        panic("Could not open %s for reading\n", filename);
1049399Sandreas.hansson@arm.com
1059399Sandreas.hansson@arm.com    // check the magic number to see if this is a gzip stream
1069399Sandreas.hansson@arm.com    unsigned char bytes[2];
1079399Sandreas.hansson@arm.com    fileStream.read((char*) bytes, 2);
1089399Sandreas.hansson@arm.com    useGzip = fileStream.good() && bytes[0] == 0x1f && bytes[1] == 0x8b;
1099399Sandreas.hansson@arm.com
1109399Sandreas.hansson@arm.com    // seek to the start of the input file and clear any flags
1119399Sandreas.hansson@arm.com    fileStream.clear();
1129399Sandreas.hansson@arm.com    fileStream.seekg(0, ifstream::beg);
1139399Sandreas.hansson@arm.com
1149399Sandreas.hansson@arm.com    createStreams();
1159399Sandreas.hansson@arm.com}
1169399Sandreas.hansson@arm.com
1179399Sandreas.hansson@arm.comvoid
1189399Sandreas.hansson@arm.comProtoInputStream::createStreams()
1199399Sandreas.hansson@arm.com{
1209399Sandreas.hansson@arm.com    // All streams should be NULL at this point
1219705Sandreas.hansson@arm.com    assert(wrappedFileStream == NULL && gzipStream == NULL &&
1229705Sandreas.hansson@arm.com           zeroCopyStream == NULL);
1239399Sandreas.hansson@arm.com
1249399Sandreas.hansson@arm.com    // Wrap the input file in a zero copy stream, that in turn is
1259399Sandreas.hansson@arm.com    // wrapped in a gzip stream if the filename ends with .gz. The
1269399Sandreas.hansson@arm.com    // latter stream is in turn wrapped in a coded stream
1279705Sandreas.hansson@arm.com    wrappedFileStream = new io::IstreamInputStream(&fileStream);
1289399Sandreas.hansson@arm.com    if (useGzip) {
1299705Sandreas.hansson@arm.com        gzipStream = new io::GzipInputStream(wrappedFileStream);
1309705Sandreas.hansson@arm.com        zeroCopyStream = gzipStream;
1319399Sandreas.hansson@arm.com    } else {
1329705Sandreas.hansson@arm.com        zeroCopyStream = wrappedFileStream;
1339399Sandreas.hansson@arm.com    }
1349399Sandreas.hansson@arm.com
1359399Sandreas.hansson@arm.com    uint32_t magic_check;
1369705Sandreas.hansson@arm.com    io::CodedInputStream codedStream(zeroCopyStream);
1379705Sandreas.hansson@arm.com    if (!codedStream.ReadLittleEndian32(&magic_check) ||
1389399Sandreas.hansson@arm.com        magic_check != magicNumber)
1399399Sandreas.hansson@arm.com        panic("Input file %s is not a valid gem5 proto format.\n",
1409399Sandreas.hansson@arm.com              fileName);
1419399Sandreas.hansson@arm.com}
1429399Sandreas.hansson@arm.com
1439399Sandreas.hansson@arm.comvoid
1449399Sandreas.hansson@arm.comProtoInputStream::destroyStreams()
1459399Sandreas.hansson@arm.com{
1469399Sandreas.hansson@arm.com    // As the compression is optional, see if the stream exists
1479399Sandreas.hansson@arm.com    if (gzipStream != NULL) {
1489399Sandreas.hansson@arm.com        delete gzipStream;
1499399Sandreas.hansson@arm.com        gzipStream = NULL;
1509399Sandreas.hansson@arm.com    }
1519705Sandreas.hansson@arm.com    delete wrappedFileStream;
1529705Sandreas.hansson@arm.com    wrappedFileStream = NULL;
1539705Sandreas.hansson@arm.com
1549399Sandreas.hansson@arm.com    zeroCopyStream = NULL;
1559399Sandreas.hansson@arm.com}
1569399Sandreas.hansson@arm.com
1579399Sandreas.hansson@arm.com
1589399Sandreas.hansson@arm.comProtoInputStream::~ProtoInputStream()
1599399Sandreas.hansson@arm.com{
1609399Sandreas.hansson@arm.com    destroyStreams();
1619399Sandreas.hansson@arm.com    fileStream.close();
1629399Sandreas.hansson@arm.com}
1639399Sandreas.hansson@arm.com
1649399Sandreas.hansson@arm.com
1659399Sandreas.hansson@arm.comvoid
1669399Sandreas.hansson@arm.comProtoInputStream::reset()
1679399Sandreas.hansson@arm.com{
1689399Sandreas.hansson@arm.com    destroyStreams();
1699399Sandreas.hansson@arm.com    // seek to the start of the input file and clear any flags
1709399Sandreas.hansson@arm.com    fileStream.clear();
1719399Sandreas.hansson@arm.com    fileStream.seekg(0, ifstream::beg);
1729399Sandreas.hansson@arm.com    createStreams();
1739399Sandreas.hansson@arm.com}
1749399Sandreas.hansson@arm.com
1759399Sandreas.hansson@arm.combool
1769399Sandreas.hansson@arm.comProtoInputStream::read(Message& msg)
1779399Sandreas.hansson@arm.com{
1789399Sandreas.hansson@arm.com    // Read a message from the stream by getting the size, using it as
1799399Sandreas.hansson@arm.com    // a limit when parsing the message, then popping the limit again
1809399Sandreas.hansson@arm.com    uint32_t size;
1819705Sandreas.hansson@arm.com
1829705Sandreas.hansson@arm.com    // Due to the byte limit of the coded stream we create it for
1839705Sandreas.hansson@arm.com    // every single mesage (based on forum discussions around the size
1849705Sandreas.hansson@arm.com    // limitation)
1859705Sandreas.hansson@arm.com    io::CodedInputStream codedStream(zeroCopyStream);
1869705Sandreas.hansson@arm.com    if (codedStream.ReadVarint32(&size)) {
1879705Sandreas.hansson@arm.com        io::CodedInputStream::Limit limit = codedStream.PushLimit(size);
1889705Sandreas.hansson@arm.com        if (msg.ParseFromCodedStream(&codedStream)) {
1899705Sandreas.hansson@arm.com            codedStream.PopLimit(limit);
1909399Sandreas.hansson@arm.com            // All went well, the message is parsed and the limit is
1919399Sandreas.hansson@arm.com            // popped again
1929399Sandreas.hansson@arm.com            return true;
1939399Sandreas.hansson@arm.com        } else {
1949399Sandreas.hansson@arm.com            panic("Unable to read message from coded stream %s\n",
1959399Sandreas.hansson@arm.com                  fileName);
1969399Sandreas.hansson@arm.com        }
1979399Sandreas.hansson@arm.com    }
1989399Sandreas.hansson@arm.com
1999399Sandreas.hansson@arm.com    return false;
2009399Sandreas.hansson@arm.com}
201