2 /// \file r_bookmark.cc
3 /// Record parsing class for the phone browser bookmarks database.
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"
35 using namespace Barry::Protocol
;
39 ///////////////////////////////////////////////////////////////////////////////
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
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 }
72 const unsigned char* Bookmark::ParseStruct1Field(const unsigned char *begin
,
73 const unsigned char *end
,
77 const uint8_t type
= *begin
;
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
;
93 // not sure where id->bookmark_id links to, so ignore
102 const VarStringField
*f
= (const VarStringField
*) begin
;
103 begin
+= VARSTRING_FIELD_HEADER_SIZE
;
107 const uint16_t size
= be_btohs(f
->be_size
);
109 if( f
->present
== 1) { // if field is defined
117 Name
= ParseFieldString(f
->data
, size
);
120 Icon
= ParseFieldString(f
->data
, size
);
123 throw std::logic_error("Check cases");
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,
135 // example with the A5, before modification to add '?'
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:
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;
155 //const BookmarkFolders *f = (const BookmarkFolders*) begin;
156 begin
+= BOOKMARK_FOLDERS_HEADER_SIZE
;
160 // currently don't know how to link these to
161 // anything else in the device.... skipping
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);
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
;
185 DisplayMode
= (Barry::Bookmark::DisplayModeType
) *(begin
- 3);
187 if ((Barry::Bookmark::JavaScriptModeType
) *(begin
- 2) > Barry::Bookmark::JavaScriptUnknown
)
188 JavaScriptMode
= Barry::Bookmark::JavaScriptUnknown
;
190 JavaScriptMode
= (Barry::Bookmark::JavaScriptModeType
) *(begin
- 2);
192 if ((Barry::Bookmark::BrowserIdentityType
) *(begin
- 1) > Barry::Bookmark::IdentityUnknown
)
193 BrowserIdentity
= Barry::Bookmark::IdentityUnknown
;
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:
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
);
209 ddout("Bookmark parser: unknown section type: "
210 << std::hex
<< (unsigned int) type
);
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
;
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
235 Url
= ParseFieldString(field
->data
, size
);
237 // FIXME - more fields after this, but unknown meaning
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
253 if( !btohs(field
->size
) ) // if field has no size, something's up
257 const unsigned char *b
= field
->u
.raw
;
258 const unsigned char *e
= begin
;
260 // handle special cases
261 switch( field
->type
)
265 b
= ParseStruct1Field(b
, e
, ic
);
269 case BMKFC_BOOKMARK_TYPE
:
270 // above size check guarantees at least one byte,
272 if( field
->u
.raw
[0] != 'D' ) {
273 throw Error( "Bookmark::ParseField: BookmarkType is not 'D'" );
278 begin
= ParseStruct2(b
, e
, ic
);
282 // if still not handled, add to the Unknowns list
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
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
;
320 const std::string
&s
= this->*(b
->strMember
);
322 os
<< " " << b
->name
<< ": " << s
<< "\n";
324 else if( b
->timeMember
) {
325 time_t t
= this->*(b
->timeMember
);
327 os
<< " " << b
->name
<< ": " << ctime(&t
);
329 os
<< " " << b
->name
<< ": unknown\n";
334 os
<< " Name: " << Name
<< "\n";
336 os
<< " Icon: " << Icon
<< "\n";
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";
347 bool Bookmark::operator<(const Bookmark
&other
) const
349 int cmp
= Name
.compare(other
.Name
);
353 void Bookmark::Clear()
355 RecType
= GetDefaultRecType();
363 BrowserIdentity
= IdentityUnknown
;
364 DisplayMode
= DisplayUnknown
;
365 JavaScriptMode
= JavaScriptUnknown
;