--- a/CPP/7zip/Archive/Zip/ZipIn.cpp +++ a/CPP/7zip/Archive/Zip/ZipIn.cpp @@ -2,6 +2,9 @@ #include "StdAfx.h" +#include +#include + // #include #include "../../../Common/DynamicBuffer.h" @@ -13,6 +16,8 @@ #include "ZipIn.h" +#include "myPrivate.h" // global_use_utf16_conversion + #define Get16(p) GetUi16(p) #define Get32(p) GetUi32(p) #define Get64(p) GetUi64(p) @@ -91,6 +96,10 @@ HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) RINOK(FindAndReadMarker(stream, searchHeaderSizeLimit)); RINOK(stream->Seek(m_Position, STREAM_SEEK_SET, NULL)); Stream = stream; + + + /* Guess archive filename charset */ + archive_oem_charset = natspec_get_charset_by_locale(NATSPEC_DOSCS, ""); return S_OK; } @@ -445,6 +454,19 @@ void CInArchive::ReadFileName(unsigned size, AString &s) s.ReleaseBuffer(); } +void CInArchive::RecodeFileName(CItem &item) { + if (item.IsUtf8()) return; + + /* Convert filename from archive charset to current locale's charset */ + char *p = natspec_convert(item.Name.Ptr(), NULL, archive_oem_charset, 0); + if (p) { + item.Name = p; + item.SetUtf8(true); + USING_UTF8 = true; + free(p); + } +} + bool CInArchive::ReadExtra(unsigned extraSize, CExtraBlock &extraBlock, UInt64 &unpackSize, UInt64 &packSize, UInt64 &localHeaderOffset, UInt32 &diskStartNumber) { @@ -565,6 +587,7 @@ bool CInArchive::ReadLocalItem(CItemEx &item) } if (item.Name.Len() != nameSize) return false; + RecodeFileName(item); return item.LocalFullHeaderSize <= ((UInt32)1 << 16); } @@ -738,6 +761,7 @@ HRESULT CInArchive::ReadCdItem(CItemEx &item) item.ExternalAttrib = Get32(p + 34); item.LocalHeaderPos = Get32(p + 38); ReadFileName(nameSize, item.Name); + RecodeFileName(item); if (extraSize > 0) { --- a/CPP/7zip/Archive/Zip/ZipIn.h +++ a/CPP/7zip/Archive/Zip/ZipIn.h @@ -184,6 +184,9 @@ public: return false; return true; } + + const char *archive_oem_charset; + void RecodeFileName(CItem &item); }; }} --- a/CPP/7zip/Archive/Zip/ZipItem.cpp +++ a/CPP/7zip/Archive/Zip/ZipItem.cpp @@ -10,6 +10,8 @@ namespace NArchive { namespace NZip { +bool USING_UTF8 = true; + using namespace NFileHeader; bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const --- a/CPP/7zip/Archive/Zip/ZipItem.h +++ a/CPP/7zip/Archive/Zip/ZipItem.h @@ -15,6 +15,8 @@ namespace NArchive { namespace NZip { +extern bool USING_UTF8; + struct CVersion { Byte Version; --- a/CPP/7zip/Archive/Zip/ZipOut.cpp +++ a/CPP/7zip/Archive/Zip/ZipOut.cpp @@ -2,10 +2,15 @@ #include "StdAfx.h" +#include +#include + #include "../../Common/OffsetStream.h" #include "ZipOut.h" +#include "myPrivate.h" // global_use_utf16_conversion + namespace NArchive { namespace NZip { @@ -18,9 +23,24 @@ HRESULT COutArchive::Create(IOutStream *outStream) m_OutBuffer.SetStream(outStream); m_OutBuffer.Init(); + /* Guess archive filename charset */ + archive_oem_charset = natspec_get_charset_by_locale(NATSPEC_DOSCS, ""); + return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base); } +void COutArchive::RecodeFileName(CItem &item) { + if (USING_UTF8) return; + + /* Convert filename from current locale charset to archive charset. */ + char *p = natspec_convert(item.Name.Ptr(), archive_oem_charset, NULL, 0); + if (p) { + item.Name = p; + item.SetUtf8(false); + free(p); + } +} + void COutArchive::MoveCurPos(UInt64 distanceToMove) { m_CurPos += distanceToMove; // test overflow --- a/CPP/7zip/Archive/Zip/ZipOut.h +++ a/CPP/7zip/Archive/Zip/ZipOut.h @@ -81,6 +81,9 @@ public: void CreateStreamForCompressing(IOutStream **outStream); void CreateStreamForCopying(ISequentialOutStream **outStream); + + const char *archive_oem_charset; + void RecodeFileName(CItem &item); }; }} --- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp +++ a/CPP/7zip/Archive/Zip/ZipUpdate.cpp @@ -86,6 +86,8 @@ static void SetFileHeader( } else isDir = item.IsDir(); + + archive.RecodeFileName(item); item.LocalHeaderPos = archive.GetCurPos(); item.MadeByVersion.HostOS = kMadeByHostOS; @@ -353,6 +355,7 @@ static HRESULT UpdateItemOldData( item.Ntfs_ATime = ui.Ntfs_ATime; item.Ntfs_CTime = ui.Ntfs_CTime; item.NtfsTimeIsDefined = ui.NtfsTimeIsDefined; + archive.RecodeFileName(item); item.CentralExtra.RemoveUnknownSubBlocks(); item.LocalExtra.RemoveUnknownSubBlocks(); @@ -367,6 +370,8 @@ static HRESULT UpdateItemOldData( { CUpdateRange range(inArchive->GetOffsetInStream(itemEx.LocalHeaderPos), itemEx.GetLocalFullSize()); + archive.RecodeFileName(item); + // set new header position item.LocalHeaderPos = archive.GetCurPos(); --- a/makefile.linux_amd64_asm +++ a/makefile.linux_amd64_asm @@ -19,7 +19,7 @@ ASM=yasm -f elf -m amd64 -Dx64 PRE_COMPILED_HEADER=StdAfx.h.gch -LOCAL_LIBS=-lpthread +LOCAL_LIBS=-lpthread -lnatspec LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl CPU=x64 --- a/makefile.linux_any_cpu_gcc_4.X +++ a/makefile.linux_any_cpu_gcc_4.X @@ -19,7 +19,7 @@ LINK_SHARED=-fPIC -shared PRE_COMPILED_HEADER=StdAfx.h.gch -LOCAL_LIBS=-lpthread +LOCAL_LIBS=-lpthread -lnatspec LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl OBJ_CRC32=$(OBJ_CRC32_C) --- a/makefile.linux_x86_asm_gcc_4.X +++ a/makefile.linux_x86_asm_gcc_4.X @@ -22,7 +22,7 @@ ASM=nasm -f elf PRE_COMPILED_HEADER=StdAfx.h.gch -LOCAL_LIBS=-lpthread +LOCAL_LIBS=-lpthread -lnatspec LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl CPU=x86