blob: db392c891bfcd12d9ad54c2d63b12a53553d5a7c [file] [log] [blame]
Adam Lesinski282e1812014-01-23 18:17:42 -08001//
2// Copyright 2006 The Android Open Source Project
3//
4// Build resource files from raw assets.
5//
6
7#ifndef RESOURCE_TABLE_H
8#define RESOURCE_TABLE_H
9
Adam Lesinski282e1812014-01-23 18:17:42 -080010#include <map>
Adam Lesinskie572c012014-09-19 15:10:04 -070011#include <queue>
12#include <set>
Adam Lesinski282e1812014-01-23 18:17:42 -080013
Adam Lesinskide7de472014-11-03 12:03:08 -080014#include "ConfigDescription.h"
15#include "ResourceFilter.h"
16#include "SourcePos.h"
17#include "StringPool.h"
18#include "Symbol.h"
19
Adam Lesinski282e1812014-01-23 18:17:42 -080020using namespace std;
21
22class XMLNode;
23class ResourceTable;
24
25enum {
26 XML_COMPILE_STRIP_COMMENTS = 1<<0,
27 XML_COMPILE_ASSIGN_ATTRIBUTE_IDS = 1<<1,
28 XML_COMPILE_COMPACT_WHITESPACE = 1<<2,
29 XML_COMPILE_STRIP_WHITESPACE = 1<<3,
30 XML_COMPILE_STRIP_RAW_VALUES = 1<<4,
31 XML_COMPILE_UTF8 = 1<<5,
32
33 XML_COMPILE_STANDARD_RESOURCE =
34 XML_COMPILE_STRIP_COMMENTS | XML_COMPILE_ASSIGN_ATTRIBUTE_IDS
35 | XML_COMPILE_STRIP_WHITESPACE | XML_COMPILE_STRIP_RAW_VALUES
36};
37
Adam Lesinskie572c012014-09-19 15:10:04 -070038status_t compileXmlFile(const Bundle* bundle,
39 const sp<AaptAssets>& assets,
40 const String16& resourceName,
Adam Lesinski282e1812014-01-23 18:17:42 -080041 const sp<AaptFile>& target,
42 ResourceTable* table,
43 int options = XML_COMPILE_STANDARD_RESOURCE);
44
Adam Lesinskie572c012014-09-19 15:10:04 -070045status_t compileXmlFile(const Bundle* bundle,
46 const sp<AaptAssets>& assets,
47 const String16& resourceName,
Adam Lesinski282e1812014-01-23 18:17:42 -080048 const sp<AaptFile>& target,
49 const sp<AaptFile>& outTarget,
50 ResourceTable* table,
51 int options = XML_COMPILE_STANDARD_RESOURCE);
52
Adam Lesinskie572c012014-09-19 15:10:04 -070053status_t compileXmlFile(const Bundle* bundle,
54 const sp<AaptAssets>& assets,
55 const String16& resourceName,
Adam Lesinski282e1812014-01-23 18:17:42 -080056 const sp<XMLNode>& xmlTree,
57 const sp<AaptFile>& target,
58 ResourceTable* table,
59 int options = XML_COMPILE_STANDARD_RESOURCE);
60
61status_t compileResourceFile(Bundle* bundle,
62 const sp<AaptAssets>& assets,
63 const sp<AaptFile>& in,
64 const ResTable_config& defParams,
65 const bool overwrite,
66 ResourceTable* outTable);
67
68struct AccessorCookie
69{
70 SourcePos sourcePos;
71 String8 attr;
72 String8 value;
73
74 AccessorCookie(const SourcePos&p, const String8& a, const String8& v)
75 :sourcePos(p),
76 attr(a),
77 value(v)
78 {
79 }
80};
81
Adam Lesinskie572c012014-09-19 15:10:04 -070082// Holds the necessary information to compile the
83// resource.
84struct CompileResourceWorkItem {
85 String16 resourceName;
86 String8 resPath;
87 sp<AaptFile> file;
88};
89
Adam Lesinski282e1812014-01-23 18:17:42 -080090class ResourceTable : public ResTable::Accessor
91{
92public:
Adam Lesinski833f3cc2014-06-18 15:06:01 -070093 // The type of package to build.
94 enum PackageType {
95 App,
96 System,
97 SharedLibrary,
98 AppFeature
99 };
100
Adam Lesinski282e1812014-01-23 18:17:42 -0800101 class Package;
102 class Type;
103 class Entry;
104
Adam Lesinski833f3cc2014-06-18 15:06:01 -0700105 ResourceTable(Bundle* bundle, const String16& assetsPackage, PackageType type);
106
107 const String16& getAssetsPackage() const {
108 return mAssetsPackage;
109 }
Adam Lesinski282e1812014-01-23 18:17:42 -0800110
Adam Lesinskie572c012014-09-19 15:10:04 -0700111 /**
112 * Returns the queue of resources that need to be compiled.
113 * This is only used for resources that have been generated
114 * during the compilation phase. If they were just added
115 * to the AaptAssets, then they may be skipped over
116 * and would mess up iteration order for the existing
117 * resources.
118 */
119 queue<CompileResourceWorkItem>& getWorkQueue() {
120 return mWorkQueue;
121 }
122
Adam Lesinski282e1812014-01-23 18:17:42 -0800123 status_t addIncludedResources(Bundle* bundle, const sp<AaptAssets>& assets);
124
125 status_t addPublic(const SourcePos& pos,
126 const String16& package,
127 const String16& type,
128 const String16& name,
129 const uint32_t ident);
130
131 status_t addEntry(const SourcePos& pos,
132 const String16& package,
133 const String16& type,
134 const String16& name,
135 const String16& value,
136 const Vector<StringPool::entry_style_span>* style = NULL,
137 const ResTable_config* params = NULL,
138 const bool doSetIndex = false,
139 const int32_t format = ResTable_map::TYPE_ANY,
140 const bool overwrite = false);
141
142 status_t startBag(const SourcePos& pos,
143 const String16& package,
144 const String16& type,
145 const String16& name,
146 const String16& bagParent,
147 const ResTable_config* params = NULL,
148 bool overlay = false,
149 bool replace = false,
150 bool isId = false);
151
152 status_t addBag(const SourcePos& pos,
153 const String16& package,
154 const String16& type,
155 const String16& name,
156 const String16& bagParent,
157 const String16& bagKey,
158 const String16& value,
159 const Vector<StringPool::entry_style_span>* style = NULL,
160 const ResTable_config* params = NULL,
161 bool replace = false,
162 bool isId = false,
163 const int32_t format = ResTable_map::TYPE_ANY);
164
165 bool hasBagOrEntry(const String16& package,
166 const String16& type,
167 const String16& name) const;
168
169 bool hasBagOrEntry(const String16& package,
170 const String16& type,
171 const String16& name,
172 const ResTable_config& config) const;
173
174 bool hasBagOrEntry(const String16& ref,
175 const String16* defType = NULL,
176 const String16* defPackage = NULL);
177
178 bool appendComment(const String16& package,
179 const String16& type,
180 const String16& name,
181 const String16& comment,
182 bool onlyIfEmpty = false);
183
184 bool appendTypeComment(const String16& package,
185 const String16& type,
186 const String16& name,
187 const String16& comment);
188
189 void canAddEntry(const SourcePos& pos,
190 const String16& package, const String16& type, const String16& name);
191
192 size_t size() const;
193 size_t numLocalResources() const;
194 bool hasResources() const;
195
Adam Lesinski82a2dd82014-09-17 18:34:15 -0700196 status_t modifyForCompat(const Bundle* bundle);
Adam Lesinskie572c012014-09-19 15:10:04 -0700197 status_t modifyForCompat(const Bundle* bundle,
198 const String16& resourceName,
199 const sp<AaptFile>& file,
200 const sp<XMLNode>& root);
Adam Lesinski82a2dd82014-09-17 18:34:15 -0700201
Adam Lesinski27f69f42014-08-21 13:19:12 -0700202 sp<AaptFile> flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
203 const bool isBase);
Adam Lesinski282e1812014-01-23 18:17:42 -0800204
205 static inline uint32_t makeResId(uint32_t packageId,
206 uint32_t typeId,
207 uint32_t nameId)
208 {
209 return nameId | (typeId<<16) | (packageId<<24);
210 }
211
212 static inline uint32_t getResId(const sp<Package>& p,
213 const sp<Type>& t,
214 uint32_t nameId);
215
216 uint32_t getResId(const String16& package,
217 const String16& type,
218 const String16& name,
219 bool onlyPublic = true) const;
220
221 uint32_t getResId(const String16& ref,
222 const String16* defType = NULL,
223 const String16* defPackage = NULL,
224 const char** outErrorMsg = NULL,
225 bool onlyPublic = true) const;
226
227 static bool isValidResourceName(const String16& s);
228
229 bool stringToValue(Res_value* outValue, StringPool* pool,
230 const String16& str,
231 bool preserveSpaces, bool coerceType,
232 uint32_t attrID,
233 const Vector<StringPool::entry_style_span>* style = NULL,
234 String16* outStr = NULL, void* accessorCookie = NULL,
235 uint32_t attrType = ResTable_map::TYPE_ANY,
236 const String8* configTypeName = NULL,
237 const ConfigDescription* config = NULL);
238
239 status_t assignResourceIds();
240 status_t addSymbols(const sp<AaptSymbols>& outSymbols = NULL);
Adam Lesinskia01a9372014-03-20 18:04:57 -0700241 void addLocalization(const String16& name, const String8& locale, const SourcePos& src);
Adam Lesinski282e1812014-01-23 18:17:42 -0800242 status_t validateLocalizations(void);
243
Adam Lesinski27f69f42014-08-21 13:19:12 -0700244 status_t flatten(Bundle* bundle, const sp<const ResourceFilter>& filter,
245 const sp<AaptFile>& dest, const bool isBase);
Adam Lesinskide898ff2014-01-29 18:20:45 -0800246 status_t flattenLibraryTable(const sp<AaptFile>& dest, const Vector<sp<Package> >& libs);
Adam Lesinski282e1812014-01-23 18:17:42 -0800247
248 void writePublicDefinitions(const String16& package, FILE* fp);
249
250 virtual uint32_t getCustomResource(const String16& package,
251 const String16& type,
252 const String16& name) const;
253 virtual uint32_t getCustomResourceWithCreation(const String16& package,
254 const String16& type,
255 const String16& name,
256 const bool createIfNeeded);
257 virtual uint32_t getRemappedPackage(uint32_t origPackage) const;
258 virtual bool getAttributeType(uint32_t attrID, uint32_t* outType);
259 virtual bool getAttributeMin(uint32_t attrID, uint32_t* outMin);
260 virtual bool getAttributeMax(uint32_t attrID, uint32_t* outMax);
261 virtual bool getAttributeKeys(uint32_t attrID, Vector<String16>* outKeys);
262 virtual bool getAttributeEnum(uint32_t attrID,
263 const char16_t* name, size_t nameLen,
264 Res_value* outValue);
265 virtual bool getAttributeFlags(uint32_t attrID,
266 const char16_t* name, size_t nameLen,
267 Res_value* outValue);
268 virtual uint32_t getAttributeL10N(uint32_t attrID);
269
270 virtual bool getLocalizationSetting();
271 virtual void reportError(void* accessorCookie, const char* fmt, ...);
272
273 void setCurrentXmlPos(const SourcePos& pos) { mCurrentXmlPos = pos; }
274
275 class Item {
276 public:
277 Item() : isId(false), format(ResTable_map::TYPE_ANY), bagKeyId(0), evaluating(false)
278 { memset(&parsedValue, 0, sizeof(parsedValue)); }
279 Item(const SourcePos& pos,
280 bool _isId,
281 const String16& _value,
282 const Vector<StringPool::entry_style_span>* _style = NULL,
283 int32_t format = ResTable_map::TYPE_ANY);
284 Item(const Item& o) : sourcePos(o.sourcePos),
285 isId(o.isId), value(o.value), style(o.style),
286 format(o.format), bagKeyId(o.bagKeyId), evaluating(false) {
287 memset(&parsedValue, 0, sizeof(parsedValue));
288 }
289 ~Item() { }
290
291 Item& operator=(const Item& o) {
292 sourcePos = o.sourcePos;
293 isId = o.isId;
294 value = o.value;
295 style = o.style;
296 format = o.format;
297 bagKeyId = o.bagKeyId;
298 parsedValue = o.parsedValue;
299 return *this;
300 }
301
302 SourcePos sourcePos;
303 mutable bool isId;
304 String16 value;
305 Vector<StringPool::entry_style_span> style;
306 int32_t format;
307 uint32_t bagKeyId;
308 mutable bool evaluating;
309 Res_value parsedValue;
310 };
311
312 class Entry : public RefBase {
313 public:
314 Entry(const String16& name, const SourcePos& pos)
315 : mName(name), mType(TYPE_UNKNOWN),
316 mItemFormat(ResTable_map::TYPE_ANY), mNameIndex(-1), mPos(pos)
317 { }
Adam Lesinski82a2dd82014-09-17 18:34:15 -0700318
319 Entry(const Entry& entry);
Adam Lesinski978ab9d2014-09-24 19:02:52 -0700320 Entry& operator=(const Entry& entry);
Adam Lesinski82a2dd82014-09-17 18:34:15 -0700321
Adam Lesinski282e1812014-01-23 18:17:42 -0800322 virtual ~Entry() { }
323
324 enum type {
325 TYPE_UNKNOWN = 0,
326 TYPE_ITEM,
327 TYPE_BAG
328 };
329
330 String16 getName() const { return mName; }
331 type getType() const { return mType; }
332
333 void setParent(const String16& parent) { mParent = parent; }
334 String16 getParent() const { return mParent; }
335
336 status_t makeItABag(const SourcePos& sourcePos);
337
338 status_t emptyBag(const SourcePos& sourcePos);
339
340 status_t setItem(const SourcePos& pos,
341 const String16& value,
342 const Vector<StringPool::entry_style_span>* style = NULL,
343 int32_t format = ResTable_map::TYPE_ANY,
344 const bool overwrite = false);
345
346 status_t addToBag(const SourcePos& pos,
347 const String16& key, const String16& value,
348 const Vector<StringPool::entry_style_span>* style = NULL,
349 bool replace=false, bool isId = false,
350 int32_t format = ResTable_map::TYPE_ANY);
351
Adam Lesinski82a2dd82014-09-17 18:34:15 -0700352 status_t removeFromBag(const String16& key);
353
Adam Lesinski282e1812014-01-23 18:17:42 -0800354 // Index of the entry's name string in the key pool.
355 int32_t getNameIndex() const { return mNameIndex; }
356 void setNameIndex(int32_t index) { mNameIndex = index; }
357
358 const Item* getItem() const { return mType == TYPE_ITEM ? &mItem : NULL; }
359 const KeyedVector<String16, Item>& getBag() const { return mBag; }
360
361 status_t generateAttributes(ResourceTable* table,
362 const String16& package);
363
364 status_t assignResourceIds(ResourceTable* table,
365 const String16& package);
366
367 status_t prepareFlatten(StringPool* strings, ResourceTable* table,
368 const String8* configTypeName, const ConfigDescription* config);
369
370 status_t remapStringValue(StringPool* strings);
371
372 ssize_t flatten(Bundle*, const sp<AaptFile>& data, bool isPublic);
373
374 const SourcePos& getPos() const { return mPos; }
375
376 private:
377 String16 mName;
378 String16 mParent;
379 type mType;
380 Item mItem;
381 int32_t mItemFormat;
382 KeyedVector<String16, Item> mBag;
383 int32_t mNameIndex;
384 uint32_t mParentId;
385 SourcePos mPos;
386 };
387
388 class ConfigList : public RefBase {
389 public:
390 ConfigList(const String16& name, const SourcePos& pos)
391 : mName(name), mPos(pos), mPublic(false), mEntryIndex(-1) { }
392 virtual ~ConfigList() { }
393
394 String16 getName() const { return mName; }
395 const SourcePos& getPos() const { return mPos; }
396
397 void appendComment(const String16& comment, bool onlyIfEmpty = false);
398 const String16& getComment() const { return mComment; }
399
400 void appendTypeComment(const String16& comment);
401 const String16& getTypeComment() const { return mTypeComment; }
402
403 // Index of this entry in its Type.
404 int32_t getEntryIndex() const { return mEntryIndex; }
405 void setEntryIndex(int32_t index) { mEntryIndex = index; }
406
407 void setPublic(bool pub) { mPublic = pub; }
408 bool getPublic() const { return mPublic; }
409 void setPublicSourcePos(const SourcePos& pos) { mPublicSourcePos = pos; }
410 const SourcePos& getPublicSourcePos() { return mPublicSourcePos; }
411
412 void addEntry(const ResTable_config& config, const sp<Entry>& entry) {
413 mEntries.add(config, entry);
414 }
415
416 const DefaultKeyedVector<ConfigDescription, sp<Entry> >& getEntries() const { return mEntries; }
417 private:
418 const String16 mName;
419 const SourcePos mPos;
420 String16 mComment;
421 String16 mTypeComment;
422 bool mPublic;
423 SourcePos mPublicSourcePos;
424 int32_t mEntryIndex;
425 DefaultKeyedVector<ConfigDescription, sp<Entry> > mEntries;
426 };
427
428 class Public {
429 public:
430 Public() : sourcePos(), ident(0) { }
431 Public(const SourcePos& pos,
432 const String16& _comment,
433 uint32_t _ident)
434 : sourcePos(pos),
435 comment(_comment), ident(_ident) { }
436 Public(const Public& o) : sourcePos(o.sourcePos),
437 comment(o.comment), ident(o.ident) { }
438 ~Public() { }
439
440 Public& operator=(const Public& o) {
441 sourcePos = o.sourcePos;
442 comment = o.comment;
443 ident = o.ident;
444 return *this;
445 }
446
447 SourcePos sourcePos;
448 String16 comment;
449 uint32_t ident;
450 };
451
452 class Type : public RefBase {
453 public:
454 Type(const String16& name, const SourcePos& pos)
455 : mName(name), mFirstPublicSourcePos(NULL), mPublicIndex(-1), mIndex(-1), mPos(pos)
456 { }
457 virtual ~Type() { delete mFirstPublicSourcePos; }
458
459 status_t addPublic(const SourcePos& pos,
460 const String16& name,
461 const uint32_t ident);
462
463 void canAddEntry(const String16& name);
464
465 String16 getName() const { return mName; }
466 sp<Entry> getEntry(const String16& entry,
467 const SourcePos& pos,
468 const ResTable_config* config = NULL,
469 bool doSetIndex = false,
470 bool overlay = false,
471 bool autoAddOverlay = false);
472
473 const SourcePos& getFirstPublicSourcePos() const { return *mFirstPublicSourcePos; }
474
475 int32_t getPublicIndex() const { return mPublicIndex; }
476
477 int32_t getIndex() const { return mIndex; }
478 void setIndex(int32_t index) { mIndex = index; }
479
480 status_t applyPublicEntryOrder();
481
482 const SortedVector<ConfigDescription>& getUniqueConfigs() const { return mUniqueConfigs; }
483
484 const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; }
485 const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; }
486
487 const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; }
488
489 const SourcePos& getPos() const { return mPos; }
490 private:
491 String16 mName;
492 SourcePos* mFirstPublicSourcePos;
493 DefaultKeyedVector<String16, Public> mPublic;
494 SortedVector<ConfigDescription> mUniqueConfigs;
495 DefaultKeyedVector<String16, sp<ConfigList> > mConfigs;
496 Vector<sp<ConfigList> > mOrderedConfigs;
497 SortedVector<String16> mCanAddEntries;
498 int32_t mPublicIndex;
499 int32_t mIndex;
500 SourcePos mPos;
501 };
502
503 class Package : public RefBase {
504 public:
Adam Lesinski833f3cc2014-06-18 15:06:01 -0700505 Package(const String16& name, size_t packageId);
Adam Lesinski282e1812014-01-23 18:17:42 -0800506 virtual ~Package() { }
507
508 String16 getName() const { return mName; }
509 sp<Type> getType(const String16& type,
510 const SourcePos& pos,
511 bool doSetIndex = false);
512
Adam Lesinski833f3cc2014-06-18 15:06:01 -0700513 size_t getAssignedId() const { return mPackageId; }
Adam Lesinski282e1812014-01-23 18:17:42 -0800514
515 const ResStringPool& getTypeStrings() const { return mTypeStrings; }
516 uint32_t indexOfTypeString(const String16& s) const { return mTypeStringsMapping.valueFor(s); }
517 const sp<AaptFile> getTypeStringsData() const { return mTypeStringsData; }
518 status_t setTypeStrings(const sp<AaptFile>& data);
519
520 const ResStringPool& getKeyStrings() const { return mKeyStrings; }
521 uint32_t indexOfKeyString(const String16& s) const { return mKeyStringsMapping.valueFor(s); }
522 const sp<AaptFile> getKeyStringsData() const { return mKeyStringsData; }
523 status_t setKeyStrings(const sp<AaptFile>& data);
524
525 status_t applyPublicTypeOrder();
526
527 const DefaultKeyedVector<String16, sp<Type> >& getTypes() const { return mTypes; }
528 const Vector<sp<Type> >& getOrderedTypes() const { return mOrderedTypes; }
529
530 private:
531 status_t setStrings(const sp<AaptFile>& data,
532 ResStringPool* strings,
533 DefaultKeyedVector<String16, uint32_t>* mappings);
534
535 const String16 mName;
Adam Lesinski833f3cc2014-06-18 15:06:01 -0700536 const size_t mPackageId;
Adam Lesinski282e1812014-01-23 18:17:42 -0800537 DefaultKeyedVector<String16, sp<Type> > mTypes;
538 Vector<sp<Type> > mOrderedTypes;
539 sp<AaptFile> mTypeStringsData;
540 sp<AaptFile> mKeyStringsData;
541 ResStringPool mTypeStrings;
542 ResStringPool mKeyStrings;
543 DefaultKeyedVector<String16, uint32_t> mTypeStringsMapping;
544 DefaultKeyedVector<String16, uint32_t> mKeyStringsMapping;
545 };
546
Adam Lesinskide7de472014-11-03 12:03:08 -0800547 void getDensityVaryingResources(KeyedVector<Symbol, Vector<SymbolDefinition> >& resources);
548
Adam Lesinski282e1812014-01-23 18:17:42 -0800549private:
550 void writePublicDefinitions(const String16& package, FILE* fp, bool pub);
551 sp<Package> getPackage(const String16& package);
552 sp<Type> getType(const String16& package,
553 const String16& type,
554 const SourcePos& pos,
555 bool doSetIndex = false);
556 sp<Entry> getEntry(const String16& package,
557 const String16& type,
558 const String16& name,
559 const SourcePos& pos,
560 bool overlay,
561 const ResTable_config* config = NULL,
562 bool doSetIndex = false);
563 sp<const Entry> getEntry(uint32_t resID,
564 const ResTable_config* config = NULL) const;
Adam Lesinskie572c012014-09-19 15:10:04 -0700565 sp<ConfigList> getConfigList(const String16& package,
566 const String16& type,
567 const String16& name) const;
Adam Lesinski282e1812014-01-23 18:17:42 -0800568 const Item* getItem(uint32_t resID, uint32_t attrID) const;
569 bool getItemValue(uint32_t resID, uint32_t attrID,
570 Res_value* outValue);
Adam Lesinski82a2dd82014-09-17 18:34:15 -0700571 bool isAttributeFromL(uint32_t attrId);
Adam Lesinski282e1812014-01-23 18:17:42 -0800572
573
574 String16 mAssetsPackage;
Adam Lesinski833f3cc2014-06-18 15:06:01 -0700575 PackageType mPackageType;
Adam Lesinski282e1812014-01-23 18:17:42 -0800576 sp<AaptAssets> mAssets;
Adam Lesinski833f3cc2014-06-18 15:06:01 -0700577 uint32_t mTypeIdOffset;
Adam Lesinski282e1812014-01-23 18:17:42 -0800578 DefaultKeyedVector<String16, sp<Package> > mPackages;
579 Vector<sp<Package> > mOrderedPackages;
Adam Lesinski282e1812014-01-23 18:17:42 -0800580 size_t mNumLocal;
581 SourcePos mCurrentXmlPos;
582 Bundle* mBundle;
583
584 // key = string resource name, value = set of locales in which that name is defined
Adam Lesinskia01a9372014-03-20 18:04:57 -0700585 map<String16, map<String8, SourcePos> > mLocalizations;
Adam Lesinskie572c012014-09-19 15:10:04 -0700586 queue<CompileResourceWorkItem> mWorkQueue;
Adam Lesinski282e1812014-01-23 18:17:42 -0800587};
588
589#endif