@@ -103,29 +103,34 @@ func buildHuffmanCodes(root *Node) (map[rune]string, error) {
103
103
}
104
104
105
105
// rebuildHuffmanTree reconstructs the Huffman tree from Huffman codes
106
- func rebuildHuffmanTree (codes map [rune ]string ) (* Node , error ) {
107
- var root * Node
106
+ func rebuildHuffmanTree (root * Node , codes map [rune ]string ) error {
108
107
for char , code := range codes {
109
- if root == nil {
110
- root = & Node {}
111
- }
112
- current := root
113
- for _ , bit := range code {
114
- if bit == '0' {
115
- if current .left == nil {
116
- current .left = & Node {}
117
- }
118
- current = current .left
119
- } else if bit == '1' {
120
- if current .right == nil {
121
- current .right = & Node {}
122
- }
123
- current = current .right
108
+ insertNode (root , char , code )
109
+ }
110
+ return nil
111
+ }
112
+
113
+ // insertNode inserts a node into the Huffman tree based on the given code
114
+ func insertNode (root * Node , char rune , code string ) {
115
+ if root == nil {
116
+ root = & Node {}
117
+ }
118
+
119
+ current := root
120
+ for _ , bit := range code {
121
+ if bit == '0' {
122
+ if current .left == nil {
123
+ current .left = & Node {}
124
+ }
125
+ current = current .left
126
+ } else if bit == '1' {
127
+ if current .right == nil {
128
+ current .right = & Node {}
124
129
}
130
+ current = current .right
125
131
}
126
- current .char = char
127
132
}
128
- return root , nil
133
+ current . char = char
129
134
}
130
135
131
136
// Zip compresses files using Huffman coding and returns a compressed file object.
@@ -140,28 +145,9 @@ func Zip(files []utils.File) (utils.File, error) {
140
145
141
146
// Create raw content buffer
142
147
var rawContent bytes.Buffer
143
- for _ , file := range files {
144
- // Write filename length and filename
145
- filenameLen := uint32 (len (file .Name ))
146
- err := binary .Write (& rawContent , binary .BigEndian , filenameLen )
147
- if err != nil {
148
- return utils.File {}, err
149
- }
150
- _ , err = rawContent .WriteString (file .Name )
151
- if err != nil {
152
- return utils.File {}, err
153
- }
154
-
155
- // Write content length and content
156
- contentLen := uint32 (len (file .Content ))
157
- err = binary .Write (& rawContent , binary .BigEndian , contentLen )
158
- if err != nil {
159
- return utils.File {}, err
160
- }
161
- _ , err = rawContent .Write (file .Content )
162
- if err != nil {
163
- return utils.File {}, err
164
- }
148
+ err = createContentBuffer (files , & rawContent )
149
+ if err != nil {
150
+ return utils.File {}, err
165
151
}
166
152
167
153
// Compress rawContent using Huffman coding
@@ -177,7 +163,10 @@ func Zip(files []utils.File) (utils.File, error) {
177
163
if err != nil {
178
164
return utils.File {}, err
179
165
}
180
- compressedContent := compressData (rawContent .Bytes (), codes )
166
+ compressedContent , err := compressData (rawContent .Bytes (), codes )
167
+ if err != nil {
168
+ return utils.File {}, err
169
+ }
181
170
182
171
// Write compressed content length to buffer
183
172
err = binary .Write (& buf , binary .BigEndian , uint32 (len (compressedContent )))
@@ -196,25 +185,60 @@ func Zip(files []utils.File) (utils.File, error) {
196
185
return utils.File {}, err
197
186
}
198
187
// Write Huffman codes to buffer
188
+ err = writeHuffmanCodesToBuffer (codes , & buf )
189
+ if err != nil {
190
+ return utils.File {}, err
191
+ }
192
+
193
+ return utils.File {
194
+ Name : "compressed.bin" ,
195
+ Content : buf .Bytes (),
196
+ }, nil
197
+ }
198
+
199
+ func writeHuffmanCodesToBuffer (codes map [rune ]string , buf * bytes.Buffer ) error {
199
200
for char , code := range codes {
200
- err = binary .Write (& buf , binary .BigEndian , char )
201
+ err : = binary .Write (buf , binary .BigEndian , char )
201
202
if err != nil {
202
- return utils. File {}, err
203
+ return err
203
204
}
204
- err = binary .Write (& buf , binary .BigEndian , uint32 (len (code )))
205
+ err = binary .Write (buf , binary .BigEndian , uint32 (len (code )))
205
206
if err != nil {
206
- return utils. File {}, err
207
+ return err
207
208
}
208
209
_ , err = buf .WriteString (code )
209
210
if err != nil {
210
- return utils. File {}, err
211
+ return err
211
212
}
212
213
}
214
+ return nil
215
+ }
213
216
214
- return utils.File {
215
- Name : "compressed.bin" ,
216
- Content : buf .Bytes (),
217
- }, nil
217
+ func createContentBuffer (files []utils.File , rawContent * bytes.Buffer ) error {
218
+ for _ , file := range files {
219
+ // Write filename length and filename
220
+ filenameLen := uint32 (len (file .Name ))
221
+ err := binary .Write (rawContent , binary .BigEndian , filenameLen )
222
+ if err != nil {
223
+ return err
224
+ }
225
+ _ , err = rawContent .WriteString (file .Name )
226
+ if err != nil {
227
+ return err
228
+ }
229
+
230
+ // Write content length and content
231
+ contentLen := uint32 (len (file .Content ))
232
+ err = binary .Write (rawContent , binary .BigEndian , contentLen )
233
+ if err != nil {
234
+ return err
235
+ }
236
+ _ , err = rawContent .Write (file .Content )
237
+ if err != nil {
238
+ return err
239
+ }
240
+ }
241
+ return nil
218
242
}
219
243
220
244
// Unzip decompresses a compressed file using Huffman coding and returns individual files.
@@ -250,110 +274,134 @@ func Unzip(file utils.File) ([]utils.File, error) {
250
274
return nil , err
251
275
}
252
276
253
- // Read Huffman codes
254
277
codes := make (map [rune ]string )
255
- for i := uint32 (0 ); i < codesLength ; i ++ {
256
- var char rune
257
- err = binary .Read (buf , binary .BigEndian , & char )
258
- if err != nil {
259
- return nil , err
260
- }
261
- var codeLength uint32
262
- err = binary .Read (buf , binary .BigEndian , & codeLength )
263
- if err != nil {
264
- return nil , err
265
- }
266
- code := make ([]byte , codeLength )
267
- _ , err = buf .Read (code )
268
- if err != nil {
269
- return nil , err
270
- }
271
- codes [char ] = string (code )
272
- }
278
+ // Read Huffman codes
279
+ readHuffManCodes (& codes , buf , codesLength )
273
280
274
281
// Rebuild Huffman tree using codes
275
- var root * Node
282
+ var root Node
276
283
if len (codes ) > 0 {
277
- root , err = rebuildHuffmanTree (codes )
284
+ err = rebuildHuffmanTree (& root , codes )
278
285
if err != nil {
279
286
return nil , err
280
287
}
281
288
}
282
289
283
- decompressedContent := decompressData (compressedContent , root )
290
+ decompressedContent := decompressData (compressedContent , & root )
284
291
285
292
// Parse decompressed content to extract files
286
293
decompressedContentBuf := bytes .NewBuffer (decompressedContent )
287
- for f := uint32 (0 ); f < numFiles ; f ++ {
294
+ err = parseDecompressedContent (& files , & numFiles , decompressedContentBuf )
295
+
296
+ if err != nil {
297
+ return nil , err
298
+ }
299
+
300
+ return files , nil
301
+ }
302
+
303
+ func parseDecompressedContent (files * []utils.File , numFiles * uint32 , decompressedContentBuf * bytes.Buffer ) error {
304
+ for f := uint32 (0 ); f < * numFiles ; f ++ {
288
305
// Read filename length
289
306
var nameLength uint32
290
- err = binary .Read (decompressedContentBuf , binary .BigEndian , & nameLength )
307
+ err : = binary .Read (decompressedContentBuf , binary .BigEndian , & nameLength )
291
308
if err != nil {
292
- return nil , err
309
+ return err
293
310
}
294
311
// Read filename
295
312
name := make ([]byte , nameLength )
296
313
_ , err = decompressedContentBuf .Read (name )
297
314
if err != nil {
298
- return nil , err
315
+ return err
299
316
}
300
317
// Read content length
301
318
var contentLength uint32
302
319
err = binary .Read (decompressedContentBuf , binary .BigEndian , & contentLength )
303
320
if err != nil {
304
- return nil , err
321
+ return err
305
322
}
306
323
// Read content
307
324
content := make ([]byte , contentLength )
308
325
_ , err = decompressedContentBuf .Read (content )
309
326
if err != nil {
310
- return nil , err
327
+ return err
311
328
}
312
- files = append (files , utils.File {
329
+ * files = append (* files , utils.File {
313
330
Name : string (name ),
314
331
Content : content ,
315
332
})
316
333
}
334
+ return nil
335
+ }
317
336
318
- return files , nil
337
+ func readHuffManCodes (codes * map [rune ]string , buf * bytes.Buffer , codesLength uint32 ) error {
338
+ for i := uint32 (0 ); i < codesLength ; i ++ {
339
+ var char rune
340
+ err := binary .Read (buf , binary .BigEndian , & char )
341
+ if err != nil {
342
+ return err
343
+ }
344
+ var codeLength uint32
345
+ err = binary .Read (buf , binary .BigEndian , & codeLength )
346
+ if err != nil {
347
+ return err
348
+ }
349
+ code := make ([]byte , codeLength )
350
+ _ , err = buf .Read (code )
351
+ if err != nil {
352
+ return err
353
+ }
354
+ (* codes )[char ] = string (code )
355
+ }
356
+ return nil
319
357
}
320
358
321
359
// compressData compresses data using Huffman codes.
322
- func compressData (data []byte , codes map [rune ]string ) []byte {
360
+ func compressData (data []byte , codes map [rune ]string ) ( []byte , error ) {
323
361
var buf bytes.Buffer
324
362
var bitBuffer uint64
325
363
var bitLength uint
326
364
for _ , b := range data {
327
365
code := codes [rune (b )]
328
- for _ , bit := range code {
329
- bitBuffer <<= 1
330
- bitLength ++
331
- if bit == '1' {
332
- bitBuffer |= 1
333
- }
334
- if bitLength == 64 {
335
- err := binary .Write (& buf , binary .BigEndian , bitBuffer )
336
- if err != nil {
337
- return nil
338
- }
339
- bitBuffer = 0
340
- bitLength = 0
341
- }
366
+ err := compressBits (& code , & buf , & bitBuffer , & bitLength )
367
+ if err != nil {
368
+ return nil , err
342
369
}
343
370
}
344
371
if bitLength > 0 {
345
372
bitBuffer <<= (64 - bitLength )
346
373
err := binary .Write (& buf , binary .BigEndian , bitBuffer )
347
374
if err != nil {
348
- return nil
375
+ return nil , fmt . Errorf ( "failed to write bit buffer: %v" , err )
349
376
}
350
377
}
351
- return buf .Bytes ()
378
+ return buf .Bytes (), nil
379
+ }
380
+
381
+ func compressBits (code * string , buf * bytes.Buffer , bitBuffer * uint64 , bitLength * uint ) error {
382
+ for _ , bit := range * code {
383
+ * bitBuffer <<= 1
384
+ * bitLength ++
385
+ if bit == '1' {
386
+ * bitBuffer |= 1
387
+ }
388
+ if * bitLength == 64 {
389
+ err := binary .Write (buf , binary .BigEndian , bitBuffer )
390
+ if err != nil {
391
+ return fmt .Errorf ("failed to write bit buffer: %v" , err )
392
+ }
393
+ * bitBuffer = 0
394
+ * bitLength = 0
395
+ }
396
+ }
397
+ return nil
352
398
}
353
399
354
400
// decompressData decompresses data using Huffman codes.
355
401
func decompressData (data []byte , root * Node ) []byte {
402
+
356
403
var buf bytes.Buffer
404
+
357
405
if root == nil {
358
406
return buf .Bytes ()
359
407
}
0 commit comments