ziplib을 사용했을 때 entry로 폴더 안의 파일들을 구성한다.
프로젝트에서는 여기에 들어가는 파일을 file stream으로 미리 생성해놓고, 해당 경로의 파일을 entry로 넣어서 처리한다.
하지만 그러면 stream으로 생성해놓은 필요없는 파일이 남아있기 때문에 이를 처리하려고 한다.
input stream없이 바로 entry 생성하기
mkdir((filepath + filename + "3MF").c_str());
generateContentTypes(filepath + filename + "3MF");
mkdir((filepath + filename + "3MF" + "/_rels").c_str());
generateRelations(filepath + filename + "3MF" + "/_rels");
mkdir((filepath + filename + "3MF" + "/3D").c_str());
generate3DModel(filepath + filename + "3MF" + "/3D", vertexVectors, faceVectors);
// ziplib
string Sample3MFPath = filepath + filename + "3MF";
filename = appendExtensionIfNeeded(filename, ".3mf");
ZipArchive::Ptr archive = ZipFile::Open(filepath + filename);
archive->RemoveEntry("_rels/.rels");
archive->RemoveEntry("3D/3dmodel.model");
archive->RemoveEntry("[Content_Types].xml");
ZipArchiveEntry::Ptr entry = archive->CreateEntry("_rels/.rels");
ZipArchiveEntry::Ptr entry2 = archive->CreateEntry("3D/3dmodel.model");
ZipArchiveEntry::Ptr entry3 = archive->CreateEntry("[Content_Types].xml");
assert(entry != nullptr);
assert(entry2 != nullptr);
assert(entry3 != nullptr);
std::ifstream contentStream(Sample3MFPath + "/_rels/.rels", std::ios::binary);
entry->SetCompressionStream(contentStream);
std::ifstream contentStream2(Sample3MFPath + "/3D/3dmodel.model", std::ios::binary);
entry2->SetCompressionStream(contentStream2);
std::ifstream contentStream3(Sample3MFPath + "/[Content_Types].xml", std::ios::binary);
entry3->SetCompressionStream(contentStream3);
ZipFile::SaveAndClose(archive, filepath + filename);
위 코드블럭이 3mf 형태로 3d model을 출력하기 위해서 ziplib을 사용하고 있다
mkdir((filepath + filename + "3MF").c_str());
generateContentTypes(filepath + filename + "3MF");
mkdir((filepath + filename + "3MF" + "/_rels").c_str());
generateRelations(filepath + filename + "3MF" + "/_rels");
mkdir((filepath + filename + "3MF" + "/3D").c_str());
generate3DModel(filepath + filename + "3MF" + "/3D", vertexVectors, faceVectors);
여기서 mkdir로 폴더를 생성하고
generateContentTypes에서 3d 파일인 xml 형태의 파일이 생성된다.
이 과정을 생략하고 바로 zip파일의 entry에 넣기를 원하는 것이다
파일의 content를 통째로 가져와서, entry로 넣어보자
stringstream 사용하기
std::ifstream contentStream(Sample3MFPath + "/_rels/.rels", std::ios::binary);
stringstream content;
content << R"(<?xml version="1.0" encoding="UTF-8"?>
<model unit="millimeter" xml:lang="en-US" xmlns="http://schemas.microsoft.com/3dmanufacturing/core/2015/02">
<resources>
<object id="1" type="model">
<mesh>
<vertices>
)";
entry->SetCompressionStream(contentStream);
entry->SetCompressionStream(content);
이렇게 string stream으로 변수를 생성하고 데이터를 넣은 뒤
entry에 넣어서 시도해보자
빌드해서 .rels 파일에 데이터가 들어있는지 확인한다
빌드한 3mf을 zip파일로 변경해서 확인해보면 내부가 텅 비어있다...
아무래도 set compression stream을 두 번 적용한 것이 문제가 되는 듯 하다
ifstream 제거하기
파일 데이터를 직접 넣는다면 iftream으로 파일을 읽어서 생성할 필요가 없으니 아예 string stream으로 변경해서 작업해보자
std::stringstream contentStream;
contentStream << R"(<?xml version="1.0" encoding="UTF-8"?>
<model unit="millimeter" xml:lang="en-US" xmlns="http://schemas.microsoft.com/3dmanufacturing/core/2015/02">
<resources>
<object id="1" type="model">
<mesh>
<vertices>
)";
entry->SetCompressionStream(contentStream);
이렇게 오로지 string stream만 이용해보자
만들어진 3mf 파일을 zip 파일로 바꾸어 열어보니 내용이 잘 들어간 상태로 만들어지는 걸 볼 수 있다
이런 식으로 나머지 파일들도 처리하면 될 것이다
// ziplib
string Sample3MFPath = filepath + filename + "3MF";
filename = appendExtensionIfNeeded(filename, ".3mf");
ZipArchive::Ptr archive = ZipFile::Open(filepath + filename);
archive->RemoveEntry("_rels/.rels");
archive->RemoveEntry("3D/3dmodel.model");
archive->RemoveEntry("[Content_Types].xml");
ZipArchiveEntry::Ptr entry = archive->CreateEntry("_rels/.rels");
ZipArchiveEntry::Ptr entry2 = archive->CreateEntry("3D/3dmodel.model");
ZipArchiveEntry::Ptr entry3 = archive->CreateEntry("[Content_Types].xml");
assert(entry != nullptr);
assert(entry2 != nullptr);
assert(entry3 != nullptr);
std::stringstream contentStream;
contentStream << R"(<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Type="http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel" Target="/3D/3dmodel.model" Id="rel0"/>
</Relationships>
)";
entry->SetCompressionStream(contentStream);
std::stringstream contentStream2;
contentStream2 << R"(<?xml version="1.0" encoding="UTF-8"?>
<model unit="millimeter" xml:lang="en-US" xmlns="http://schemas.microsoft.com/3dmanufacturing/core/2015/02">
<resources>
<object id="1" type="model">
<mesh>
<vertices>
)";
entry2->SetCompressionStream(contentStream2);
std::stringstream contentStream3;
contentStream3 << R"(<?xml version="1.0" encoding="UTF-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />
<Default Extension="model" ContentType="application/vnd.ms-package.3dmanufacturing-3dmodel+xml" />
</Types>
)";
entry3->SetCompressionStream(contentStream3);
이렇게 string stream으로 처리하면 파일 데이터가 들어간 상태로 zip 파일이 잘 생성된다.