forked from toniebox-reverse-engineering/hackiebox_cfw
-
Notifications
You must be signed in to change notification settings - Fork 0
/
BoxTonies.cpp
158 lines (139 loc) · 5.99 KB
/
BoxTonies.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include "BoxTonies.h"
bool BoxTonies::loadTonieByUid(uint8_t uid[8]) {
uint8_t path[strlen(CONTENT_BASE)+16+1+1];
sprintf(
(char*)path,
"%s%02X%02X%02X%02X/%02X%02X%02X%02X",
CONTENT_BASE,
uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], uid[7]
);
memcpy(currentUid, uid, 8);
if (loadTonieByPath(path)) {
return true;
}
return false;
}
bool BoxTonies::loadTonieByPath(uint8_t* path) {
bool ret = true;
clearHeader();
Log.info("Load Tonie from path %s...", path);
if (tonieFile.open((char*)path, FA_OPEN_EXISTING | FA_READ)) {
uint8_t buffer[512]; //TODO: buffer >512 size may scramble the stream 4096 block needed
uint32_t read = tonieFile.read(buffer, sizeof(buffer));
uint16_t bufferLen = read;
if (read > 0) {
uint16_t cursor = 0;
uint8_t readBytes;
uint8_t magicBytes[] = { 0x00, 0x00, 0x0F, 0xFC };//==4092 which is the length of the protobuf block
if (memcmp(magicBytes, buffer, 4) == 0) {
cursor += 4;
while (cursor < bufferLen-1) {
uint8_t fieldId = buffer[cursor]>>3;
uint8_t fieldType = buffer[cursor]&0b00000111;
cursor++;
if (fieldId == 1 && fieldType == 2) { //Audio data SHA-1 hash
uint64_t size = readVariant(&buffer[cursor], bufferLen-cursor, readBytes);
cursor += readBytes;
if (size == 20) {
memcpy(&header.hash[0], &buffer[cursor], size);
cursor += size;
} else {
Log.error("... hash length should be 20 but is %i", size);
ret = false;
break;
}
} else if (fieldId == 2 && fieldType == 0) { //Audio data length in bytes
header.audioLength = (uint32_t)readVariant(&buffer[cursor], bufferLen-cursor, readBytes);
cursor += readBytes;
} else if (fieldId == 3 && fieldType == 0) { //Audio-ID of OGG audio file, which is the unix time stamp of file creation
header.audioId = (uint32_t)readVariant(&buffer[cursor], bufferLen-cursor, readBytes);
cursor += readBytes;
} else if (fieldId == 4 && fieldType == 2) { //[array of variant] Ogg page numbers for Chapters
uint8_t blockEnd = (uint8_t)readVariant(&buffer[cursor], bufferLen-cursor, readBytes);
cursor += readBytes;
blockEnd += cursor;
uint16_t blockStart = cursor;
header.audioChapterCount = 0;
while(cursor<blockEnd) {
uint32_t chapter = (uint32_t)readVariant(&buffer[cursor], bufferLen-cursor, readBytes);
cursor += readBytes;
header.audioChapterCount++;
}
cursor = blockStart; //reread
for (uint8_t i = 0; i < header.audioChapterCount; i++) {
uint32_t chapter = (uint32_t)readVariant(&buffer[cursor], bufferLen-cursor, readBytes);
cursor += readBytes;
header.audioChapters[i] = chapter;
}
} else if (fieldId == 5 && fieldType == 2) { //fill bytes „00“ up to <header_len>
uint64_t fillByteCount = readVariant(&buffer[cursor], bufferLen-cursor, readBytes);
cursor += readBytes;
if (fillByteCount + cursor != 4096) {
Log.error("... Header length should be 4096 but is %i", fillByteCount + cursor);
ret = false;
}
break; //everything read.
} else {
Log.error("... found unexpected protobuf field with id=%i and type=%i", fieldId, fieldType);
ret = false;
//clear header
break;
}
}
logTonieHeader();
} else {
Log.error("... unexpected beginning of file %X %X %X %X", buffer[0], buffer[1], buffer[2], buffer[3]);
ret = false;
}
} else {
Log.error("... couldn't data from file");
ret = false;
}
tonieFile.close();
} else {
Log.error("... couldn't open Tonie");
ret = false;
}
if (!ret) {
clearHeader();
}
return ret;
}
void BoxTonies::clearHeader() {
//header.hash = {0}; //TODO
header.audioLength = 0;
header.audioId = 0;
header.audioChapterCount = 0;
for (uint8_t i=0; i<99; i++) {
header.audioChapters[i] = 0;
}
}
uint64_t BoxTonies::readVariant(uint8_t* buffer, uint16_t length, uint8_t& readBytes) {
uint64_t ret = 0;
readBytes = 0;
while (readBytes<length) {
uint8_t data = buffer[readBytes];
ret |= ((uint64_t)(data & 0x7F)) << (7 * readBytes);
readBytes++;
if ((data & 0x80) == 0)
break;
};
return ret;
}
void BoxTonies::logTonieHeader() {
Log.info("Tonie Header");
Log.disableNewline(true);
Log.info(" Hash:");
for (uint8_t i = 0; i < 20; i++){
Log.printf(" %x", header.hash[i]);
}
Log.disableNewline(false);
Log.println();
Log.info(" Length: %ib", header.audioLength);
Log.info(" ID: %i", header.audioId);
Log.info(" Chapters: %i", header.audioChapterCount);
for (uint8_t i = 0; i < header.audioChapterCount; i++){
Log.info(" %i: %i", i+1, header.audioChapters[i]);
}
Log.println();
}