Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / Archive / Tar / TarOut.cpp
1 // TarOut.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "Common/IntToString.h"\r
6 \r
7 #include "../../Common/StreamUtils.h"\r
8 \r
9 #include "TarOut.h"\r
10 \r
11 namespace NArchive {\r
12 namespace NTar {\r
13 \r
14 HRESULT COutArchive::WriteBytes(const void *buffer, UInt32 size)\r
15 {\r
16   return WriteStream(m_Stream, buffer, size);\r
17 }\r
18 \r
19 void COutArchive::Create(ISequentialOutStream *outStream)\r
20 {\r
21   m_Stream = outStream;\r
22 }\r
23 \r
24 static AString MakeOctalString(UInt64 value)\r
25 {\r
26   char s[32];\r
27   ConvertUInt64ToString(value, s, 8);\r
28   return AString(s) + ' ';\r
29 }\r
30 \r
31 static void MyStrNCpy(char *dest, const char *src, int size)\r
32 {\r
33   for (int i = 0; i < size; i++)\r
34   {\r
35     char c = src[i];\r
36     dest[i] = c;\r
37     if (c == 0)\r
38       break;\r
39   }\r
40 }\r
41 \r
42 static bool MakeOctalString8(char *s, UInt32 value)\r
43 {\r
44   AString tempString = MakeOctalString(value);\r
45 \r
46   const int kMaxSize = 8;\r
47   if (tempString.Length() >= kMaxSize)\r
48     return false;\r
49   int numSpaces = kMaxSize - (tempString.Length() + 1);\r
50   for(int i = 0; i < numSpaces; i++)\r
51     s[i] = ' ';\r
52   MyStringCopy(s + numSpaces, (const char *)tempString);\r
53   return true;\r
54 }\r
55 \r
56 static void MakeOctalString12(char *s, UInt64 value)\r
57 {\r
58   AString tempString  = MakeOctalString(value);\r
59   const int kMaxSize = 12;\r
60   if (tempString.Length() > kMaxSize)\r
61   {\r
62     // GNU extension;\r
63     s[0] = (char)(Byte)0x80;\r
64     s[1] = s[2] = s[3] = 0;\r
65     for (int i = 0; i < 8; i++, value <<= 8)\r
66       s[4 + i] = (char)(value >> 56);\r
67     return;\r
68   }\r
69   int numSpaces = kMaxSize - tempString.Length();\r
70   for(int i = 0; i < numSpaces; i++)\r
71     s[i] = ' ';\r
72   memmove(s + numSpaces, (const char *)tempString, tempString.Length());\r
73 }\r
74 \r
75 static bool CopyString(char *dest, const AString &src, int maxSize)\r
76 {\r
77   if (src.Length() >= maxSize)\r
78     return false;\r
79   MyStringCopy(dest, (const char *)src);\r
80   return true;\r
81 }\r
82 \r
83 #define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_FAIL; }\r
84 \r
85 HRESULT COutArchive::WriteHeaderReal(const CItem &item)\r
86 {\r
87   char record[NFileHeader::kRecordSize];\r
88   char *cur = record;\r
89   int i;\r
90   for (i = 0; i < NFileHeader::kRecordSize; i++)\r
91     record[i] = 0;\r
92 \r
93   // RETURN_IF_NOT_TRUE(CopyString(header.Name, item.Name, NFileHeader::kNameSize));\r
94   if (item.Name.Length() > NFileHeader::kNameSize)\r
95     return E_FAIL;\r
96   MyStrNCpy(cur, item.Name, NFileHeader::kNameSize);\r
97   cur += NFileHeader::kNameSize;\r
98 \r
99   RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.Mode)); cur += 8;\r
100   RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.UID)); cur += 8;\r
101   RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.GID)); cur += 8;\r
102 \r
103   MakeOctalString12(cur, item.Size); cur += 12;\r
104   MakeOctalString12(cur, item.MTime); cur += 12;\r
105   \r
106   memmove(cur, NFileHeader::kCheckSumBlanks, 8);\r
107   cur += 8;\r
108 \r
109   *cur++ = item.LinkFlag;\r
110 \r
111   RETURN_IF_NOT_TRUE(CopyString(cur, item.LinkName, NFileHeader::kNameSize));\r
112   cur += NFileHeader::kNameSize;\r
113 \r
114   memmove(cur, item.Magic, 8);\r
115   cur += 8;\r
116 \r
117   RETURN_IF_NOT_TRUE(CopyString(cur, item.User, NFileHeader::kUserNameSize));\r
118   cur += NFileHeader::kUserNameSize;\r
119   RETURN_IF_NOT_TRUE(CopyString(cur, item.Group, NFileHeader::kGroupNameSize));\r
120   cur += NFileHeader::kGroupNameSize;\r
121 \r
122 \r
123   if (item.DeviceMajorDefined)\r
124     RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMajor));\r
125   cur += 8;\r
126 \r
127   if (item.DeviceMinorDefined)\r
128     RETURN_IF_NOT_TRUE(MakeOctalString8(cur, item.DeviceMinor));\r
129   cur += 8;\r
130 \r
131 \r
132   UInt32 checkSumReal = 0;\r
133   for(i = 0; i < NFileHeader::kRecordSize; i++)\r
134     checkSumReal += Byte(record[i]);\r
135 \r
136   RETURN_IF_NOT_TRUE(MakeOctalString8(record + 148, checkSumReal));\r
137 \r
138   return WriteBytes(record, NFileHeader::kRecordSize);\r
139 }\r
140 \r
141 HRESULT COutArchive::WriteHeader(const CItem &item)\r
142 {\r
143   int nameSize = item.Name.Length();\r
144   if (nameSize < NFileHeader::kNameSize)\r
145     return WriteHeaderReal(item);\r
146 \r
147   CItem modifiedItem = item;\r
148   int nameStreamSize = nameSize + 1;\r
149   modifiedItem.Size = nameStreamSize;\r
150   modifiedItem.LinkFlag = 'L';\r
151   modifiedItem.Name = NFileHeader::kLongLink;\r
152   modifiedItem.LinkName.Empty();\r
153   RINOK(WriteHeaderReal(modifiedItem));\r
154   RINOK(WriteBytes(item.Name, nameStreamSize));\r
155   RINOK(FillDataResidual(nameStreamSize));\r
156 \r
157   modifiedItem = item;\r
158   modifiedItem.Name = item.Name.Left(NFileHeader::kNameSize - 1);\r
159   return WriteHeaderReal(modifiedItem);\r
160 }\r
161 \r
162 HRESULT COutArchive::FillDataResidual(UInt64 dataSize)\r
163 {\r
164   UInt32 lastRecordSize = UInt32(dataSize & (NFileHeader::kRecordSize - 1));\r
165   if (lastRecordSize == 0)\r
166     return S_OK;\r
167   UInt32 residualSize = NFileHeader::kRecordSize - lastRecordSize;\r
168   Byte residualBytes[NFileHeader::kRecordSize];\r
169   for (UInt32 i = 0; i < residualSize; i++)\r
170     residualBytes[i] = 0;\r
171   return WriteBytes(residualBytes, residualSize);\r
172 }\r
173 \r
174 HRESULT COutArchive::WriteFinishHeader()\r
175 {\r
176   Byte record[NFileHeader::kRecordSize];\r
177   int i;\r
178   for (i = 0; i < NFileHeader::kRecordSize; i++)\r
179     record[i] = 0;\r
180   for (i = 0; i < 2; i++)\r
181   {\r
182     RINOK(WriteBytes(record, NFileHeader::kRecordSize));\r
183   }\r
184   return S_OK;\r
185 }\r
186 \r
187 }}\r