tools: MimeDump<> can have all static members
[barry.git] / src / r_bookmark.cc
blob74f07869b56c417197a6c091ada9d5029a35c919
1 ///
2 /// \file r_bookmark.cc
3 /// Record parsing class for the phone browser bookmarks database.
4 ///
6 /*
7 Copyright (C) 2008-2010, Nicolas VIVIEN
8 Copyright (C) 2005-2010, Net Direct Inc. (http://www.netdirect.ca/)
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License in the COPYING file at the
20 root directory of this project for more details.
23 #include "r_bookmark.h"
24 #include "record-internal.h"
25 #include "protostructs.h"
26 #include "data.h"
27 #include "time.h"
28 #include "iconv.h"
29 #include "debug.h"
30 #include <ostream>
31 #include <iomanip>
32 #include <iostream>
34 using namespace std;
35 using namespace Barry::Protocol;
37 namespace Barry {
39 ///////////////////////////////////////////////////////////////////////////////
40 // Bookmark Class
42 // Bookmark Field Codes
43 #define BMKFC_BOOKMARK_TYPE 0x01
44 #define BMKFC_STRUCT1 0x11
45 #define BMKFC_STRUCT2 0x12
47 #define BMKFC_END 0xffff
49 // Bookmark Struct1 section codes
50 #define BMK1SC_HOMEPAGE_KEY 0x85 // default section on 9550...
51 // has browser dropdown grayed
52 // out
53 #define BMK1SC_BOOKMARK_ID 0x87 // when user adds a bookmark
54 #define BMK1SC_BOOKMARK_ID2 0x84 // only Nicolas sees this?
55 #define BMK1SC_NAME 0x04
56 #define BMK1SC_ICON 0x05
57 #define BMK1SC_FOLDERS 0x81
59 static FieldLink<Bookmark> BookmarkFieldLinks[] = {
60 { BMKFC_END, "End of List", 0, 0, 0, 0, 0, 0, 0, false }
63 Bookmark::Bookmark()
65 Clear();
68 Bookmark::~Bookmark()
72 const unsigned char* Bookmark::ParseStruct1Field(const unsigned char *begin,
73 const unsigned char *end,
74 const IConverter *ic)
76 // grab section type
77 const uint8_t type = *begin;
78 begin += 1;
79 if( begin > end )
80 return begin;
82 switch( type )
84 case BMK1SC_HOMEPAGE_KEY:
85 case BMK1SC_BOOKMARK_ID:
86 case BMK1SC_BOOKMARK_ID2:
88 const BookmarkId *id = (const BookmarkId*) begin;
89 begin += BOOKMARK_ID_SIZE;
90 if( begin > end )
91 return begin;
93 // not sure where id->bookmark_id links to, so ignore
94 // for now...
95 Index = id->index;
97 return begin;
99 case BMK1SC_NAME:
100 case BMK1SC_ICON:
102 const VarStringField *f = (const VarStringField*) begin;
103 begin += VARSTRING_FIELD_HEADER_SIZE;
104 if( begin > end )
105 return begin;
107 const uint16_t size = be_btohs(f->be_size);
109 if( f->present == 1) { // if field is defined
110 begin += size;
111 if( begin > end )
112 return begin;
114 switch( type )
116 case BMK1SC_NAME:
117 Name = ParseFieldString(f->data, size);
118 break;
119 case BMK1SC_ICON:
120 Icon = ParseFieldString(f->data, size);
121 break;
122 default:
123 throw std::logic_error("Check cases");
124 break;
127 else if( f->present == 0 && size > 0xA0 ) {
128 // FIXME - a size of 0xA5 seems to occasionally
129 // appear, with 5 bytes of id-looking data
130 // we just skip it here.... note this
131 // may be a different field, but it meshes
132 // itself into the ICON section somehow,
133 // that is unclear
135 // example with the A5, before modification to add '?'
136 // Type: 0x11 Data:
137 // 00000000: 85 9b ed ca 13 00 04 01 00 09 48 6f 6d 65 20 50 ..........Home P
138 // 00000010: 61 67 65 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05 00 age.............
139 // 00000020: 00 a5 b8 f0 97 e4 3a 00 00 01 ......:...
141 // example without the A5, after record modified:
142 // Type: 0x11 Data:
143 // 00000000: 85 9b ed ca 13 00 04 01 00 0a 48 6f 6d 65 20 50 ..........Home P
144 // 00000010: 61 67 65 3f 81 b9 fc f8 f6 c2 e3 a4 d5 08 01 05 age?............
145 // 00000020: 00 00 00 00 00 01 ......
148 begin += size & 0x0F;
151 return begin;
153 case BMK1SC_FOLDERS:
155 //const BookmarkFolders *f = (const BookmarkFolders*) begin;
156 begin += BOOKMARK_FOLDERS_HEADER_SIZE;
157 if( begin > end )
158 return begin;
160 // currently don't know how to link these to
161 // anything else in the device.... skipping
163 return begin;
166 case 0x08:
167 isdefined = *b;
168 b += sizeof(uint8_t);
169 if (isdefined == 1) { // if field is defined
170 const uint16_t size = be_btohs(*((const uint16_t *) b));
171 b += sizeof(uint16_t);
172 b += size;
174 break;
177 default:
178 // if we are 3 bytes away from the end, these are the
179 // display, javascript, and browser identity flags
180 // (make sure to account for the type we ate above)
181 if( (end - begin) == 2 ) {
182 if ((Barry::Bookmark::DisplayModeType) *(begin - 3) > Barry::Bookmark::DisplayUnknown)
183 DisplayMode = Barry::Bookmark::DisplayUnknown;
184 else
185 DisplayMode = (Barry::Bookmark::DisplayModeType) *(begin - 3);
187 if ((Barry::Bookmark::JavaScriptModeType) *(begin - 2) > Barry::Bookmark::JavaScriptUnknown)
188 JavaScriptMode = Barry::Bookmark::JavaScriptUnknown;
189 else
190 JavaScriptMode = (Barry::Bookmark::JavaScriptModeType) *(begin - 2);
192 if ((Barry::Bookmark::BrowserIdentityType) *(begin - 1) > Barry::Bookmark::IdentityUnknown)
193 BrowserIdentity = Barry::Bookmark::IdentityUnknown;
194 else
195 BrowserIdentity = (Barry::Bookmark::BrowserIdentityType) *(begin - 1);
197 // if we are at the beginning, this could be the 7750
198 // with its odd no-code ID... the 7750 seems to have
199 // a BOOKMARK_ID record without any code byte,
200 // so check that the data looks like this:
201 // XX XX XX XX 00
202 // with the 4 byte ID and the index of 0, being the
203 // first default bookmark
204 else if( (begin + 3) < end && begin[3] == 0 ) {
205 // recurse into ourselves
206 return ParseStruct1Field(begin + 4, end, ic);
208 else {
209 ddout("Bookmark parser: unknown section type: "
210 << std::hex << (unsigned int) type);
212 break;
215 return begin;
218 const unsigned char* Bookmark::ParseStruct2(const unsigned char *begin,
219 const unsigned char *end,
220 const IConverter *ic)
222 // first field in struct2 seems to always be the URL
224 // grab size and advance over string, checking sizes
225 const StringField *field = (const StringField*) begin;
226 begin += STRING_FIELD_HEADER_SIZE;
227 if( begin > end )
228 return begin;
230 const uint16_t size = be_btohs(field->be_size);
231 begin += sizeof(uint16_t) + size;
232 if( begin > end ) // if begin==end, we are ok
233 return begin;
235 Url = ParseFieldString(field->data, size);
237 // FIXME - more fields after this, but unknown meaning
239 return begin;
242 const unsigned char* Bookmark::ParseField(const unsigned char *begin,
243 const unsigned char *end,
244 const IConverter *ic)
246 const CommonField *field = (const CommonField *) begin;
248 // advance and check size
249 begin += COMMON_FIELD_HEADER_SIZE + btohs(field->size);
250 if( begin > end ) // if begin==end, we are ok
251 return begin;
253 if( !btohs(field->size) ) // if field has no size, something's up
254 return begin;
257 const unsigned char *b = field->u.raw;
258 const unsigned char *e = begin;
260 // handle special cases
261 switch( field->type )
263 case BMKFC_STRUCT1:
264 while (b <= e) {
265 b = ParseStruct1Field(b, e, ic);
267 return b;
269 case BMKFC_BOOKMARK_TYPE:
270 // above size check guarantees at least one byte,
271 // so this is safe
272 if( field->u.raw[0] != 'D' ) {
273 throw Error( "Bookmark::ParseField: BookmarkType is not 'D'" );
275 return begin;
277 case BMKFC_STRUCT2:
278 begin = ParseStruct2(b, e, ic);
279 return begin;
282 // if still not handled, add to the Unknowns list
283 UnknownField uf;
284 uf.type = field->type;
285 uf.data.assign((const char*)field->u.raw, btohs(field->size));
286 Unknowns.push_back(uf);
288 // return new pointer for next field
289 return begin;
292 void Bookmark::ParseHeader(const Data &data, size_t &offset)
294 // no header in Bookmark records
297 void Bookmark::ParseFields(const Data &data, size_t &offset, const IConverter *ic)
299 const unsigned char *finish = ParseCommonFields(*this,
300 data.GetData() + offset, data.GetData() + data.GetSize(), ic);
301 offset += finish - (data.GetData() + offset);
304 void Bookmark::Dump(std::ostream &os) const
306 static const char *DisplayModeName[] = { "Automatic", "Enabled", "Disabled", "Unknown" };
307 static const char *JavaScriptModeName[] = { "Automatic", "Enabled", "Disabled", "Unknown" };
308 static const char *BrowserIdentityName[] = { "Automatic", "BlackBerry", "FireFox", "Internet Explorer", "Unknown" };
310 os << "Bookmark entry: 0x" << setbase(16) << RecordId
311 << " (" << (unsigned int)RecType << ")"
312 << " (index " << (unsigned int)Index << ")\n";
314 // cycle through the type table
315 for( const FieldLink<Bookmark> *b = BookmarkFieldLinks;
316 b->type != BMKFC_END;
317 b++ )
319 if( b->strMember ) {
320 const std::string &s = this->*(b->strMember);
321 if( s.size() )
322 os << " " << b->name << ": " << s << "\n";
324 else if( b->timeMember ) {
325 time_t t = this->*(b->timeMember);
326 if( t > 0 )
327 os << " " << b->name << ": " << ctime(&t);
328 else
329 os << " " << b->name << ": unknown\n";
333 if( Name.size() )
334 os << " Name: " << Name << "\n";
335 if( Icon.size() )
336 os << " Icon: " << Icon << "\n";
337 if( Url.size() )
338 os << " Url: " << Url << "\n";
339 os << " Display mode: " << DisplayModeName[DisplayMode] << "\n";
340 os << " JavaScript mode: " << JavaScriptModeName[JavaScriptMode] << "\n";
341 os << " Browser Identity mode: " << BrowserIdentityName[BrowserIdentity] << "\n";
343 os << Unknowns;
344 os << "\n\n";
347 bool Bookmark::operator<(const Bookmark &other) const
349 int cmp = Name.compare(other.Name);
350 return cmp < 0;
353 void Bookmark::Clear()
355 RecType = GetDefaultRecType();
356 RecordId = 0;
357 Index = 0;
359 Name.clear();
360 Icon.clear();
361 Url.clear();
363 BrowserIdentity = IdentityUnknown;
364 DisplayMode = DisplayUnknown;
365 JavaScriptMode = JavaScriptUnknown;
367 Unknowns.clear();
370 } // namespace Barry