Skip to content

Commit da4bfac

Browse files
committed
ObjectReader/Writer now support .cobz extension for compressed .cob files
1 parent e54cfcd commit da4bfac

File tree

7 files changed

+129
-13
lines changed

7 files changed

+129
-13
lines changed

include/IECore/ObjectReader.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//////////////////////////////////////////////////////////////////////////
22
//
3-
// Copyright (c) 2007-2011, Image Engine Design Inc. All rights reserved.
3+
// Copyright (c) 2007-2015, Image Engine Design Inc. All rights reserved.
44
//
55
// Redistribution and use in source and binary forms, with or without
66
// modification, are permitted provided that the following conditions are
@@ -74,6 +74,7 @@ class IECORE_API ObjectReader : public Reader
7474
private :
7575

7676
static const ReaderDescription<ObjectReader> g_readerDescription;
77+
static const ReaderDescription<ObjectReader> g_compressedReaderDescription;
7778
};
7879

7980
IE_CORE_DECLAREPTR( ObjectReader );

include/IECore/ObjectWriter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class IECORE_API ObjectWriter : public Writer
7070
void constructParameters();
7171

7272
static const WriterDescription<ObjectWriter> g_writerDescription;
73+
static const WriterDescription<ObjectWriter> g_compressedWriterDescription;
7374

7475
};
7576

src/IECore/ObjectReader.cpp

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//////////////////////////////////////////////////////////////////////////
22
//
3-
// Copyright (c) 2007-2010, Image Engine Design Inc. All rights reserved.
3+
// Copyright (c) 2007-2015, Image Engine Design Inc. All rights reserved.
44
//
55
// Redistribution and use in source and binary forms, with or without
66
// modification, are permitted provided that the following conditions are
@@ -32,11 +32,16 @@
3232
//
3333
//////////////////////////////////////////////////////////////////////////
3434

35+
#include "IECore/ObjectWriter.h"
3536
#include "IECore/ObjectReader.h"
3637
#include "IECore/FileIndexedIO.h"
38+
#include "IECore/MemoryIndexedIO.h"
3739
#include "IECore/FileNameParameter.h"
3840
#include "IECore/CompoundData.h"
3941

42+
#include "boost/filesystem/convenience.hpp"
43+
#include "boost/iostreams/filter/gzip.hpp"
44+
4045
#include <cassert>
4146

4247
using namespace IECore;
@@ -45,14 +50,15 @@ using namespace boost;
4550
IE_CORE_DEFINERUNTIMETYPED( ObjectReader );
4651

4752
const Reader::ReaderDescription<ObjectReader> ObjectReader::g_readerDescription( "cob" );
53+
const Reader::ReaderDescription<ObjectReader> ObjectReader::g_compressedReaderDescription( "cobz" );
4854

4955
ObjectReader::ObjectReader() :
50-
Reader( "Reads instances of a single Object from a file with a .cob extension" )
56+
Reader( "Reads instances of a single Object from a file with a .cob or .cobz extension" )
5157
{
5258
}
5359

5460
ObjectReader::ObjectReader( const std::string &fileName ) :
55-
Reader( "Reads instances of a single Object from a file with a .cob extension" )
61+
Reader( "Reads instances of a single Object from a file with a .cob or .cobz extension" )
5662
{
5763
m_fileNameParameter->setTypedValue( fileName );
5864
}
@@ -91,7 +97,48 @@ bool ObjectReader::canRead( const std::string &fileName )
9197
ObjectPtr ObjectReader::doOperation( const CompoundObject * operands )
9298
{
9399
IndexedIOPtr io = open(fileName());
94-
return Object::load( io, "object" );
100+
101+
// is this file compressed?
102+
if( boost::filesystem::extension( boost::filesystem::path( fileName() ) ) == ".cobz" )
103+
{
104+
IndexedIOPtr objectCompressed = io->subdirectory( "objectCompressed" );
105+
106+
// read size of compressed data:
107+
size_t compressedSize;
108+
objectCompressed->read( "size", compressedSize );
109+
110+
// read the actual data
111+
std::vector<char> compressedData( compressedSize );
112+
char* cd = compressedData.data();
113+
objectCompressed->read( InternedString( "data" ), cd, compressedSize * sizeof(char) );
114+
115+
// decompress into a buffer for a MemoryIndexedIO:
116+
CharVectorDataPtr memBufferData = new CharVectorData;
117+
118+
// read compression type:
119+
std::string compressionType;
120+
objectCompressed->read( "compressionType", compressionType );
121+
122+
if( compressionType == "gzip" )
123+
{
124+
boost::iostreams::filtering_ostream decompressingStream;
125+
decompressingStream.push( boost::iostreams::gzip_decompressor() );
126+
decompressingStream.push( boost::iostreams::back_inserter( memBufferData->writable() ) );
127+
decompressingStream.write( compressedData.data(), compressedData.size() * sizeof(char) );
128+
}
129+
else
130+
{
131+
throw IECore::Exception( "ObjectReader::doOperation: unrecognized compression type " + compressionType );
132+
}
133+
134+
MemoryIndexedIOPtr mio = new MemoryIndexedIO( memBufferData, IndexedIO::rootPath, IndexedIO::Read );
135+
136+
return Object::load( mio, "object" );
137+
}
138+
else
139+
{
140+
return Object::load( io, "object" );
141+
}
95142
}
96143

97144
CompoundObjectPtr ObjectReader::readHeader()

src/IECore/ObjectWriter.cpp

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//////////////////////////////////////////////////////////////////////////
22
//
3-
// Copyright (c) 2007-2010, Image Engine Design Inc. All rights reserved.
3+
// Copyright (c) 2007-2015, Image Engine Design Inc. All rights reserved.
44
//
55
// Redistribution and use in source and binary forms, with or without
66
// modification, are permitted provided that the following conditions are
@@ -34,9 +34,14 @@
3434

3535
#include <cassert>
3636

37+
#include "boost/filesystem/convenience.hpp"
38+
#include "boost/iostreams/filter/gzip.hpp"
39+
3740
#include "IECore/ObjectWriter.h"
3841
#include "IECore/FileIndexedIO.h"
42+
#include "IECore/MemoryIndexedIO.h"
3943
#include "IECore/FileNameParameter.h"
44+
#include "IECore/NumericParameter.h"
4045
#include "IECore/CompoundParameter.h"
4146
#include "IECore/ObjectParameter.h"
4247
#include "IECore/CompoundData.h"
@@ -51,15 +56,16 @@ using namespace boost;
5156
IE_CORE_DEFINERUNTIMETYPED( ObjectWriter )
5257

5358
const Writer::WriterDescription<ObjectWriter> ObjectWriter::g_writerDescription( "cob" );
59+
const Writer::WriterDescription<ObjectWriter> ObjectWriter::g_compressedWriterDescription( "cobz" );
5460

5561
ObjectWriter::ObjectWriter()
56-
: Writer( "Writes instances of a single Object to a file with a .cob extension", ObjectTypeId )
62+
: Writer( "Writes instances of a single Object to a file with a .cob or .cobz extension", ObjectTypeId )
5763
{
5864
constructParameters();
5965
}
6066

6167
ObjectWriter::ObjectWriter( ObjectPtr object, const std::string &fileName )
62-
: Writer( "Writes instances of a single Object to a file with a .cob extension", ObjectTypeId )
68+
: Writer( "Writes instances of a single Object to a file with a .cob or .cobz extension", ObjectTypeId )
6369
{
6470
constructParameters();
6571
m_objectParameter->setValue( object );
@@ -95,8 +101,32 @@ void ObjectWriter::doWrite( const CompoundObject *operands )
95101

96102
((ObjectPtr)header)->save( io, "header" );
97103

98-
// write the object
99-
object()->save( io, "object" );
104+
if( boost::filesystem::extension( boost::filesystem::path( fileName() ) ) == ".cobz" )
105+
{
106+
// write the object to a memory buffer:
107+
MemoryIndexedIOPtr bodyIO = new MemoryIndexedIO( ConstCharVectorDataPtr(), IndexedIO::rootPath, IndexedIO::Exclusive | IndexedIO::Write );
108+
object()->save( bodyIO, "object" );
109+
110+
// compress:
111+
std::vector<char> compressedData;
112+
boost::iostreams::filtering_ostream compressingStream;
113+
compressingStream.push( boost::iostreams::gzip_compressor() );
114+
compressingStream.push(boost::iostreams::back_inserter(compressedData));
115+
compressingStream.write( bodyIO->buffer()->readable().data(), bodyIO->buffer()->readable().size() * sizeof(char) );
116+
boost::iostreams::close( compressingStream );
117+
118+
IndexedIOPtr objectCompressed = io->createSubdirectory( "objectCompressed" );
119+
objectCompressed->write( "size", compressedData.size() );
120+
objectCompressed->write( "data", compressedData.data(), compressedData.size() * sizeof(char) );
121+
122+
// write the compression type in case we want to change it later on and retain backward compatitility:
123+
objectCompressed->write( "compressionType", "gzip" );
124+
}
125+
else
126+
{
127+
// no compression, just write the object:
128+
object()->save( io, "object" );
129+
}
100130
}
101131

102132
void ObjectWriter::constructParameters()

src/IECoreHoudini/GEO_CobIOTranslator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ int GEO_CobIOTranslator::checkExtension( const char *fileName )
6767
UT_String sname( fileName );
6868

6969
/// \todo: support all extensions that can read/write any object supported by the To/FromHoudiniGeometryConverters
70-
if ( sname.fileExtension() && ( !strcmp( sname.fileExtension(), ".cob" ) || !strcmp( sname.fileExtension(), ".pdc" ) || !strcmp( sname.fileExtension(), ".ptc" ) ) )
70+
if ( sname.fileExtension() && ( !strcmp( sname.fileExtension(), ".cob" ) || !strcmp( sname.fileExtension(), ".cobz" ) || !strcmp( sname.fileExtension(), ".pdc" ) || !strcmp( sname.fileExtension(), ".ptc" ) ) )
7171
{
7272
return true;
7373
}

src/IECoreHoudini/plugin/Plugin.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ void newGeometryIO( void * )
214214
{
215215
geoextension->addExtension( "cob" );
216216
}
217+
if ( !geoextension->findExtension( "cobz" ) )
218+
{
219+
geoextension->addExtension( "cobz" );
220+
}
217221
if ( !geoextension->findExtension( "pdc" ) )
218222
{
219223
geoextension->addExtension( "pdc" );

test/IECore/ObjectWriter.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,43 @@ def testHeader( self ) :
6969
self.assertEqual( h["host"]["nodeName"].value, socket.gethostname() )
7070
self.assertEqual( h["ieCoreVersion"].value, IECore.versionString() )
7171
self.assertEqual( h["typeName"].value, "IntData" )
72-
72+
73+
def testCompressed( self ) :
74+
75+
floats = IECore.FloatVectorData( range(0,10000) )
76+
w = IECore.Writer.create( floats, "test/compressed.cobz" )
77+
78+
w.write()
79+
80+
# check FileIndexedIO contents:
81+
fio = IECore.FileIndexedIO( "test/compressed.cobz", IECore.IndexedIO.OpenMode.Read )
82+
fio.subdirectory("header")
83+
fio.subdirectory("objectCompressed")
84+
85+
# read back and check object:
86+
self.assertEqual( IECore.Reader.create( "test/compressed.cobz" ).read(), floats )
87+
88+
def testCompressedHeader( self ) :
89+
90+
o = IECore.IntData()
91+
92+
w = IECore.Writer.create( o, "test/compressed.cobz" )
93+
w["header"].getValue()["testHeaderData"] = IECore.StringData( "i am part of a header" )
94+
w["header"].getValue()["testHeaderData2"] = IECore.IntData( 100 )
95+
w.write()
96+
97+
h = IECore.Reader.create( "test/compressed.cobz" ).readHeader()
98+
99+
for k in w["header"].getValue().keys() :
100+
self.assertEqual( w["header"].getValue()[k], h[k] )
101+
102+
self.assertEqual( h["host"]["nodeName"].value, socket.gethostname() )
103+
self.assertEqual( h["ieCoreVersion"].value, IECore.versionString() )
104+
self.assertEqual( h["typeName"].value, "IntData" )
105+
73106
def tearDown( self ) :
74107

75-
for f in ( "test/compoundData.cob", "test/intData.cob" ) :
108+
for f in ( "test/compoundData.cob", "test/intData.cob", "test/compressed.cobz" ) :
76109
if os.path.isfile( f ) :
77110
os.remove( f )
78111

0 commit comments

Comments
 (0)