xref: /haiku/src/apps/haikudepot/tar/TarArchiveHeader.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
1 /*
2  * Copyright 2017, Andrew Lindesay <apl@lindesay.co.nz>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 #include "TarArchiveHeader.h"
7 
8 #include <stdio.h>
9 
10 
11 #define OFFSET_FILENAME 0
12 #define OFFSET_LENGTH 124
13 #define OFFSET_CHECKSUM 148
14 #define OFFSET_FILETYPE 156
15 
16 #define LENGTH_FILENAME 100
17 #define LENGTH_LENGTH 12
18 #define LENGTH_CHECKSUM 8
19 #define LENGTH_BLOCK 512
20 
21 
22 TarArchiveHeader::TarArchiveHeader(const BString& fileName, uint64 length,
23 		tar_file_type fileType)
24 		:
25 		fFileName(fileName),
26 		fLength(length),
27 		fFileType(fileType)
28 {
29 }
30 
31 tar_file_type
32 TarArchiveHeader::_ReadFileType(unsigned char data) {
33 	switch (data) {
34 		case 0:
35 		case '0':
36 			return TAR_FILE_TYPE_NORMAL;
37 
38 		default:
39 			return TAR_FILE_TYPE_OTHER;
40 	}
41 }
42 
43 
44 const BString
45 TarArchiveHeader::_ReadString(const unsigned char *data, size_t dataLength)
46 {
47 	uint32 actualLength = 0;
48 
49 	while (actualLength < dataLength && 0 != data[actualLength])
50 		actualLength++;
51 
52 	return BString((const char *) data, actualLength);
53 }
54 
55 /*
56  * This is an octal value represented as an ASCII string.
57  */
58 
59 static bool tar_is_octal_digit(unsigned char c)
60 {
61 	switch (c) {
62 		case '0':
63 		case '1':
64 		case '2':
65 		case '3':
66 		case '4':
67 		case '5':
68 		case '6':
69 		case '7':
70 			return true;
71 
72 		default:
73 			return false;
74 	}
75 }
76 
77 uint32
78 TarArchiveHeader::_ReadNumeric(const unsigned char *data, size_t dataLength)
79 {
80 	uint32 actualLength = 0;
81 
82 	while (actualLength < dataLength && tar_is_octal_digit(data[actualLength]))
83 		actualLength++;
84 
85 	uint32 factor = 1;
86 	uint32 result = 0;
87 
88 	for (uint32 i = 0; i < actualLength; i++) {
89 		result += (data[actualLength - (1 + i)] - '0') * factor;
90 		factor *= 8;
91 	}
92 
93 	return result;
94 }
95 
96 uint32
97 TarArchiveHeader::_CalculateChecksum(const unsigned char* block)
98 {
99 	uint32 result = 0;
100 
101 	for (uint32 i = 0; i < LENGTH_BLOCK; i++) {
102 		if (i >= OFFSET_CHECKSUM && i < OFFSET_CHECKSUM + LENGTH_CHECKSUM)
103 			result += 32;
104 		else
105 			result += block[i];
106 	}
107 
108 	return result;
109 }
110 
111 TarArchiveHeader*
112 TarArchiveHeader::CreateFromBlock(const unsigned char* block)
113 {
114 	uint32 actualChecksum = _CalculateChecksum(block);
115 	uint32 expectedChecksum = _ReadNumeric(&block[OFFSET_CHECKSUM],
116 		LENGTH_CHECKSUM);
117 
118 	if(actualChecksum != expectedChecksum) {
119 		fprintf(stderr, "tar archive header has bad checksum;"
120 			"expected %" B_PRIu32 " actual %" B_PRIu32 "\n",
121 			expectedChecksum, actualChecksum);
122 	} else {
123 		return new TarArchiveHeader(
124 			_ReadString(&block[OFFSET_FILENAME], LENGTH_FILENAME),
125 			_ReadNumeric(&block[OFFSET_LENGTH], LENGTH_LENGTH),
126 			_ReadFileType(block[OFFSET_FILETYPE]));
127 	}
128 
129 	return NULL;
130 }
131 
132 const BString&
133 TarArchiveHeader::GetFileName() const
134 {
135 	return fFileName;
136 }
137 
138 size_t
139 TarArchiveHeader::GetLength() const
140 {
141 	return fLength;
142 }
143 
144 
145 tar_file_type
146 TarArchiveHeader::GetFileType() const
147 {
148 	return fFileType;
149 }
150