2 * Copyright 2011 Aleksas Pantechovskis, <alexp.frl@gmail.com>
3 * Copyright 2011 Siarzhuk Zharski, <imker@gmx.li>
4 * All rights reserved. Distributed under the terms of the MIT License.
18 #include <Application.h>
21 #include <InterfaceDefs.h>
31 const char* kUsageMessage
= "# setmime:\n"
32 "# usage: setmime ((-dump | -dumpSniffRule | -dumpIcon | -dumpAll) "
33 "[ <signatureString> ] )\n"
34 "# | (-remove <signatureString> )\n"
35 "# | ( (-set | -force | -add) <signatureString>\n"
36 "# [ -short <short description> ] [ -long <long description> ]\n"
37 "# [ -preferredApp <preferred app path> ]\n"
38 "# [ -preferredAppSig <preferred app signature> ]\n"
39 "# [ -sniffRule <sniffRule> ]\n"
40 "# [ -extension <file suffix> ]\n"
41 "# [ -attribute <internal name>\n"
42 "# [ -attrName <public name> ] [ -attrType <type code> ]\n"
43 "# [ -attrWidth <display width> ][ -attrAlignment <position>]\n"
44 "# [ -attrViewable <bool flag> ][ -attrEditable <bool flag> ]\n"
45 "# [ -attrExtra <bool flag> ] ]\n"
46 "# [ -miniIcon <256 hex bytes> ]\n"
47 "# [ -largeIcon <1024 hex bytes> ]\n"
48 "# [ -vectorIcon <icon hex bytes> ] ... )\n"
49 "# | (-checkSniffRule <sniffRule>\n"
50 "# | -includeApps)\n";
52 const char* kHelpMessage
= "# -dump prints a specified metamime\n"
53 "# -remove removes specified metamime\n"
54 "# -add adds specified metamime and specified metamime attributes\n"
55 "# that have not yet been defined\n"
56 "# -set adds specified metamime and specified metamime attributes, \n"
57 "# overwrites the existing values of specified metamime attributes\n"
58 "# -force adds specified metamime and specified metamime attributes\n"
59 "# after first erasing all the existing attributes\n"
60 "# -dumpSniffRule prints just the MIME sniffer rule of a "
61 "specified metamime\n"
62 "# -dumpIcon prints just the icon information of a specified metamime\n"
63 "# -dumpAll prints all the information, including icons of a "
64 "specified metamime\n"
65 "# -checkSniffRule parses a MIME sniffer rule and reports any errors\n"
66 "# -includeApps will include applications\n";
68 const char* kNeedArgMessage
= "you have to specify any of "
69 "-dump[All|Icon|SnifferRule], -add, -set, "
72 const char* kWrongModeMessage
= "can only specify one of -dump, -dumpAll, "
73 "-dumpIcon, -dumpSnifferRule, -remove, "
74 "-add, -set, -force or -checkSnifferRule";
76 const char* kHelpReq
= "--help";
77 const char* kDump
= "-dump";
78 const char* kDumpSniffRule
= "-dumpSniffRule";
79 const char* kDumpIcon
= "-dumpIcon";
80 const char* kDumpAll
= "-dumpAll";
81 const char* kAdd
= "-add";
82 const char* kSet
= "-set";
83 const char* kForce
= "-force";
84 const char* kRemove
= "-remove";
85 const char* kCheckSniffRule
= "-checkSniffRule";
86 const char* kShort
= "-short";
87 const char* kLong
= "-long";
88 const char* kPreferredApp
= "-preferredApp";
89 const char* kPreferredAppSig
= "-preferredAppSig";
90 const char* kSniffRule
= "-sniffRule";
91 const char* kMiniIcon
= "-miniIcon";
92 const char* kLargeIcon
= "-largeIcon";
93 const char* kVectorIcon
= "-vectorIcon";
94 const char* kIncludeApps
= "-includeApps";
95 const char* kExtension
= "-extension";
96 const char* kAttribute
= "-attribute";
97 const char* kAttrName
= "-attrName";
98 const char* kAttrType
= "-attrType";
99 const char* kAttrWidth
= "-attrWidth";
100 const char* kAttrAlignment
= "-attrAlignment";
101 const char* kAttrViewable
= "-attrViewable";
102 const char* kAttrEditable
= "-attrEditable";
103 const char* kAttrExtra
= "-attrExtra";
106 const uint32
hash_function(const char* str
)
110 for (const char* p
= str
; *p
; p
++) {
111 h
= (h
<< 4) + (*p
& 0xFF);
122 // the list of all acceptable command-line options
140 { kHelpReq
, CmdOption::kHelp
},
142 { kDump
, CmdOption::kMode
},
143 { kDumpSniffRule
, CmdOption::kMode
},
144 { kDumpIcon
, CmdOption::kMode
},
145 { kDumpAll
, CmdOption::kMode
},
146 { kAdd
, CmdOption::kMode
},
147 { kSet
, CmdOption::kMode
},
148 { kForce
, CmdOption::kMode
},
149 { kRemove
, CmdOption::kMode
},
150 { kCheckSniffRule
, CmdOption::kMode
, true },
152 { kShort
, CmdOption::kOption
, true },
153 { kLong
, CmdOption::kOption
, true },
154 { kPreferredApp
, CmdOption::kOption
, true },
155 { kPreferredAppSig
, CmdOption::kOption
, true },
156 { kSniffRule
, CmdOption::kOption
, true },
157 { kMiniIcon
, CmdOption::kOption
, true },
158 { kLargeIcon
, CmdOption::kOption
, true },
159 { kVectorIcon
, CmdOption::kOption
, true },
160 { kIncludeApps
, CmdOption::kOption
, false },
161 { kExtension
, CmdOption::kOption
, true, true },
162 { kAttribute
, CmdOption::kAttrRoot
, true, true },
164 { kAttrName
, CmdOption::kAttrib
, true },
165 { kAttrType
, CmdOption::kAttrib
, true },
166 { kAttrWidth
, CmdOption::kAttrib
, true },
167 { kAttrAlignment
, CmdOption::kAttrib
, true },
168 { kAttrViewable
, CmdOption::kAttrib
, true },
169 { kAttrEditable
, CmdOption::kAttrib
, true },
170 { kAttrExtra
, CmdOption::kAttrib
, true }
173 // the 'hash -> value' map of arguments provided by user
174 typedef multimap
<uint32
, const char*> TUserArgs
;
175 typedef multimap
<uint32
, const char*>::iterator TUserArgsI
;
177 // user provided attributes are grouped separately in vector
178 typedef vector
<TUserArgs
> TUserAttrs
;
179 typedef vector
<TUserArgs
>::iterator TUserAttrsI
;
181 const uint32 kOpModeUndefined
= 0;
186 class Error
: public std::exception
190 Error(const char* what
, ...);
191 virtual ~Error() throw() {}
192 virtual const char* what() const throw() { return fWhat
.String(); }
196 Error::Error(const char* what
, ...)
198 const int size
= 1024;
200 va_start(args
, what
);
201 vsnprintf(fWhat
.LockBuffer(size
), size
, what
, args
);
202 fWhat
.UnlockBuffer();
209 // encapsulate the single attribute params
223 MimeAttribute(BMessage
& msg
, int32 index
);
224 MimeAttribute(TUserArgs
& args
);
225 MimeAttribute(const MimeAttribute
& src
);
227 status_t
InitCheck() { return fStatus
; }
229 MimeAttribute
& operator=(const MimeAttribute
& src
);
232 void SyncWith(TUserArgs
& args
) throw(Error
);
233 void StoreInto(BMessage
* target
);
234 const char* UserArgValue(TUserArgs
& map
, const char* name
);
236 bool IsPrintableChar(char c
)
237 { return c
>= ' ' && c
< 127 && c
!= '\'' && c
!= '\\'; }
241 MimeAttribute::MimeAttribute(BMessage
& msg
, int32 index
)
251 BString rawPublicName
;
258 { "attr:name", B_STRING_TYPE
, true, &fName
},
259 { "attr:public_name", B_STRING_TYPE
, true, &rawPublicName
},
260 { "attr:type", B_INT32_TYPE
, true, &fType
},
261 { "attr:viewable", B_BOOL_TYPE
, false, &fViewable
},
262 { "attr:editable", B_BOOL_TYPE
, false, &fEditable
},
263 { "attr:extra", B_BOOL_TYPE
, false, &fExtra
},
264 { "attr:width", B_INT32_TYPE
, false, &fWidth
},
265 { "attr:alignment", B_INT32_TYPE
, false, &fAlignment
}
268 for (size_t i
= 0; i
< sizeof(attrEntries
) / sizeof(attrEntries
[0]); i
++) {
269 switch (attrEntries
[i
].type
) {
271 fStatus
= msg
.FindString(attrEntries
[i
].name
, index
,
272 (BString
*)attrEntries
[i
].data
);
275 fStatus
= msg
.FindBool(attrEntries
[i
].name
, index
,
276 (bool*)attrEntries
[i
].data
);
279 fStatus
= msg
.FindInt32(attrEntries
[i
].name
, index
,
280 (int32
*)attrEntries
[i
].data
);
284 if (attrEntries
[i
].required
&& fStatus
!= B_OK
)
288 fPublicName
.CharacterEscape(rawPublicName
, "\'", '\\');
293 MimeAttribute::MimeAttribute(TUserArgs
& args
)
308 MimeAttribute::MimeAttribute(const MimeAttribute
& src
)
315 MimeAttribute::operator=(const MimeAttribute
& src
)
317 fStatus
= src
.fStatus
;
319 fPublicName
= src
.fPublicName
;
321 fViewable
= src
.fViewable
;
322 fEditable
= src
.fEditable
;
325 fAlignment
= src
.fAlignment
;
332 MimeAttribute::SyncWith(TUserArgs
& args
) throw(Error
)
334 const char* value
= UserArgValue(args
, kAttribute
);
336 fName
.SetTo(value
, B_MIME_TYPE_LENGTH
);
338 value
= UserArgValue(args
, kAttrName
);
340 fPublicName
.SetTo(value
, B_MIME_TYPE_LENGTH
);
342 value
= UserArgValue(args
, kAttrType
);
345 if (strlen(value
) > 2 && value
[0] == '0' && value
[1] == 'x') {
347 ss
<< setbase(16) << value
+ 2;
349 } else if (strlen(value
) == 4) {
350 for (int i
= 0; i
< 4 && value
[i
] != '\0'; i
++) {
352 fType
|= (value
[i
] != '\0' ? value
[i
] : ' ');
356 throw Error("Invalid data for %s", kAttrType
);
358 fType
= B_LENDIAN_TO_HOST_INT32(fType
);
361 value
= UserArgValue(args
, kAttrWidth
);
363 fWidth
= atoi(value
);
365 value
= UserArgValue(args
, kAttrAlignment
);
367 if (strcasecmp(value
, "right") == 0) {
368 fAlignment
= B_ALIGN_RIGHT
;
369 } else if (strcasecmp(value
, "left") == 0) {
370 fAlignment
= B_ALIGN_LEFT
;
371 } else if (strcasecmp(value
, "center") == 0) {
372 fAlignment
= B_ALIGN_CENTER
;
374 fAlignment
= atoi(value
);
377 value
= UserArgValue(args
, kAttrViewable
);
379 fViewable
= atoi(value
) != 0;
381 value
= UserArgValue(args
, kAttrEditable
);
383 fEditable
= atoi(value
) != 0;
385 value
= UserArgValue(args
, kAttrExtra
);
387 fExtra
= atoi(value
) != 0;
392 MimeAttribute::Dump()
394 uint32 type
= B_HOST_TO_LENDIAN_INT32(fType
);
395 const char* alignment
= fAlignment
== B_ALIGN_RIGHT
? "right"
396 : (fAlignment
== B_ALIGN_LEFT
? "left" : "center");
398 cout
<< " \\" << endl
<< "\t" << kAttribute
<< " \"" << fName
<< "\" "
399 << kAttrName
<< " \"" << fPublicName
<< "\"";
401 char c1
= (char)((type
>> 24) & 0xFF);
402 char c2
= (char)((type
>> 16) & 0xFF);
403 char c3
= (char)((type
>> 8) & 0xFF);
404 char c4
= (char)(type
& 0xFF);
406 ios::fmtflags flags
= cout
.flags();
408 cout
<< " \\" << endl
<< "\t\t" << kAttrType
;
409 if (IsPrintableChar(c1
) && IsPrintableChar(c2
) &&
410 IsPrintableChar(c3
) && IsPrintableChar(c4
))
411 cout
<< " '" << c1
<< c2
<< c3
<< c4
<< "' ";
413 cout
<< "0x" << hex
<< type
;
415 cout
<< " " << kAttrWidth
<< " " << fWidth
416 << " " << kAttrAlignment
<< " " << alignment
;
418 cout
<< " \\" << endl
<< "\t\t" << kAttrViewable
<< " " << fViewable
419 << " " << kAttrEditable
<< " " << fEditable
420 << " " << kAttrExtra
<< " " << fExtra
;
427 MimeAttribute::StoreInto(BMessage
* target
)
434 { "attr:name", B_STRING_TYPE
, fName
.String() },
435 { "attr:public_name", B_STRING_TYPE
, fPublicName
.String() },
436 { "attr:type", B_INT32_TYPE
, &fType
},
437 { "attr:viewable", B_BOOL_TYPE
, &fViewable
},
438 { "attr:editable", B_BOOL_TYPE
, &fEditable
},
439 { "attr:extra", B_BOOL_TYPE
, &fExtra
},
440 { "attr:width", B_INT32_TYPE
, &fWidth
},
441 { "attr:alignment", B_INT32_TYPE
, &fAlignment
}
444 for (size_t i
= 0; i
< sizeof(attrEntries
) / sizeof(attrEntries
[0]); i
++) {
445 switch (attrEntries
[i
].type
) {
447 fStatus
= target
->AddString(attrEntries
[i
].name
,
448 (const char*)attrEntries
[i
].data
);
451 fStatus
= target
->AddBool(attrEntries
[i
].name
,
452 (bool*)attrEntries
[i
].data
);
455 fStatus
= target
->AddInt32(attrEntries
[i
].name
,
456 *(int32
*)attrEntries
[i
].data
);
467 MimeAttribute::UserArgValue(TUserArgs
& map
, const char* name
)
469 TUserArgsI i
= map
.find(hash_function(name
));
472 return i
->second
!= NULL
? i
->second
: "";
478 // the work-horse of the app - the class encapsulates extended info readed
479 // from the mime type and do all edit and dump operations
481 class MimeType
: public BMimeType
{
484 MimeType(char** argv
) throw (Error
);
487 void Process() throw (Error
);
490 status_t
_InitCheck();
491 void _SetTo(const char* mimetype
) throw (Error
);
492 void _PurgeProperties();
493 void _Init(char** argv
) throw (Error
);
494 void _DumpIcon(uint8
*iconData
, size_t iconSize
);
495 void _Dump(const char* mimetype
) throw (Error
);
496 void _DoEdit() throw (Error
);
497 void _SetIcon(const char* iconData
, int32 iconSize
);
499 const char* _UserArgValue(const char* name
);
502 const char* fToolName
;
504 // configurable MimeType properties
513 size_t fVectorIconSize
;
515 map
<uint32
, BString
> fExtensions
;
516 map
<uint32
, MimeAttribute
> fAttributes
;
518 // user provided arguments
519 TUserArgs fUserArguments
;
520 TUserAttrs fUserAttributes
;
522 // operation mode switches and flags
532 bool fCheckSniffRule
;
536 MimeType::MimeType(char** argv
) throw (Error
)
544 fOpMode(kOpModeUndefined
),
553 fCheckSniffRule(false)
555 fToolName
= strrchr(argv
[0], '/');
556 fToolName
= fToolName
== NULL
? argv
[0] : fToolName
+ 1;
562 MimeType::~MimeType()
571 MimeType::_Init(char** argv
) throw (Error
)
573 // fill the helper map of options - for quick lookup of arguments
574 map
<uint32
, const CmdOption
*> cmdOptionsMap
;
575 for (size_t i
= 0; i
< sizeof(gCmdOptions
) / sizeof(gCmdOptions
[0]); i
++)
576 cmdOptionsMap
.insert(pair
<uint32
, CmdOption
*>(
577 hash_function(gCmdOptions
[i
].fName
), &gCmdOptions
[i
]));
579 // parse the command line arguments
580 for (char** arg
= argv
; *arg
; arg
++) {
581 // non-option arguments are assumed as signature
584 throw Error("mime signature already specified: '%s'", Type());
590 // check op.modes, options and attribs
591 uint32 key
= hash_function(*arg
);
593 map
<uint32
, const CmdOption
*>::iterator I
= cmdOptionsMap
.find(key
);
594 if (I
== cmdOptionsMap
.end())
595 throw Error("unknown option '%s'", *arg
);
597 switch (I
->second
->fType
) {
598 case CmdOption::kHelp
:
599 cerr
<< kUsageMessage
;
600 throw Error(kHelpMessage
);
602 case CmdOption::kMode
:
603 // op.modes are exclusive - no simultaneous possible
604 if (fOpMode
!= kOpModeUndefined
)
605 throw Error(kWrongModeMessage
);
608 if (hash_function(I
->second
->fName
) != hash_function(kCheckSniffRule
))
610 // else -> fallthrough, CheckRule works both as mode and Option
611 case CmdOption::kOption
:
613 const char* name
= *arg
;
614 const char* param
= NULL
;
615 if (I
->second
->fNeedArg
) {
617 throw Error("argument required for '%s'", name
);
621 TUserArgsI A
= fUserArguments
.find(key
);
622 if (A
!= fUserArguments
.end() && !I
->second
->fNonExclusive
)
623 throw Error("option '%s' already specified", name
);
625 fUserArguments
.insert(
626 pair
<uint32
, const char*>(key
, param
));
630 case CmdOption::kAttrRoot
:
632 throw Error("attribute name should be specified");
634 fUserAttributes
.resize(fUserAttributes
.size() + 1);
635 fUserAttributes
.back().insert(
636 pair
<uint32
, const char*>(key
, *arg
));
639 case CmdOption::kAttrib
:
641 const char* name
= *arg
;
642 if (fUserAttributes
.size() <= 0)
643 throw Error("'%s' allowed only after the '%s' <name>",
646 if (!*++arg
|| **arg
== '-')
647 throw Error("'%s', argument should be specified", name
);
649 TUserArgsI A
= fUserAttributes
.back().find(key
);
650 if (A
!= fUserAttributes
.back().end())
651 throw Error("'%s' for attribute '%s' already specified",
654 fUserAttributes
.back().insert(
655 pair
<uint32
, const char*>(key
, *arg
));
660 throw Error("internal error. wrong mode: %d", I
->second
->fType
);
664 // check some mutual exclusive conditions
665 if (fOpMode
== kOpModeUndefined
)
666 throw Error(kNeedArgMessage
);
668 if (Type() != NULL
&& InitCheck() != B_OK
)
669 throw Error("error instantiating mime for '%s': %s",
670 Type(), strerror(InitCheck()));
672 fDoAdd
= fOpMode
== hash_function(kAdd
);
673 fDoSet
= fOpMode
== hash_function(kSet
);
674 fDoForce
= fOpMode
== hash_function(kForce
);
675 fDoRemove
= fOpMode
== hash_function(kRemove
);
676 fDumpNormal
= fOpMode
== hash_function(kDump
);
677 fDumpRule
= fOpMode
== hash_function(kDumpSniffRule
);
678 fDumpIcon
= fOpMode
== hash_function(kDumpIcon
);
679 fDumpAll
= fOpMode
== hash_function(kDumpAll
);
680 fCheckSniffRule
= fOpMode
== hash_function(kCheckSniffRule
);
682 if (fDoAdd
|| fDoSet
|| fDoForce
|| fDoRemove
) {
684 throw Error("signature should be specified");
687 throw Error("mime for '%s' is not valid", Type());
689 } else if (fDumpNormal
|| fDumpRule
|| fDumpIcon
|| fDumpAll
) {
690 if (Type() != NULL
) {
692 throw Error("mime for '%s' is not valid", Type());
695 throw Error("mime for '%s' is not installed", Type());
699 // finally force to load mime-specific fileds
705 MimeType::_InitCheck()
707 return fStatus
!= B_OK
? fStatus
: BMimeType::InitCheck();
712 MimeType::_PurgeProperties()
716 fPrefApp
.Truncate(0);
717 fPrefAppSig
.Truncate(0);
718 fSniffRule
.Truncate(0);
735 MimeType::_DumpIcon(uint8
*iconData
, size_t iconSize
)
737 // bitmap icons ASCII art :)
738 int lineLimit
= iconSize
== B_MINI_ICON
* B_MINI_ICON
739 ? B_MINI_ICON
: B_LARGE_ICON
;
741 ios::fmtflags flags
= cout
.flags();
743 for (size_t i
= 0; i
< iconSize
; i
++) {
744 if (i
% lineLimit
== 0 && i
!= iconSize
- 1)
745 cout
<< "\\" << endl
;
747 cout
<< hex
<< setfill('0') << setw(2) << (uint16
) iconData
[i
];
755 MimeType::_SetIcon(const char* iconData
, int32 iconSize
)
758 BRect
rect(0, 0, iconSize
- 1, iconSize
- 1);
762 if (fSmallIcon
== NULL
)
763 fSmallIcon
= new BBitmap(rect
, B_COLOR_8_BIT
);
764 bits
= (uint8
*) fSmallIcon
->Bits();
767 if (fBigIcon
== NULL
)
768 fBigIcon
= new BBitmap(rect
, B_COLOR_8_BIT
);
769 bits
= (uint8
*) fBigIcon
->Bits();
775 fVectorIconSize
= -iconSize
;
776 bits
= fVectorIcon
= (uint8
*) malloc(fVectorIconSize
);
781 throw Error("cannot create icon of size %d", iconSize
);
783 size_t dataSize
= iconSize
< 0 ? -iconSize
/ 2 : iconSize
* iconSize
;
785 for (size_t i
= 0; i
< dataSize
; i
++) {
788 ss
<< setbase(16) << iconData
[i
* 2] << iconData
[i
* 2 + 1];
790 bits
[i
] = uint8(val
& 0xff);
794 SetIcon(fVectorIcon
, dataSize
);
796 SetIcon(iconSize
== B_MINI_ICON
? fSmallIcon
: fBigIcon
,
797 (icon_size
) iconSize
);
802 MimeType::_SetTo(const char* mimetype
) throw (Error
)
804 if (mimetype
== NULL
)
805 return; // iterate all types - nothing to load ATM
807 if (BMimeType::SetTo(mimetype
) != B_OK
)
808 throw Error("failed to set mimetype to '%s'", mimetype
);
812 char buffer
[B_MIME_TYPE_LENGTH
] = { 0 };
813 if (GetShortDescription(buffer
) == B_OK
)
814 fShort
.SetTo(buffer
, B_MIME_TYPE_LENGTH
);
816 if (GetLongDescription(buffer
) == B_OK
)
817 fLong
.SetTo(buffer
, B_MIME_TYPE_LENGTH
);
820 if (GetAppHint(&ref
) == B_OK
) {
822 fPrefApp
.SetTo(path
.Path(), B_MIME_TYPE_LENGTH
);
825 if (GetPreferredApp(buffer
, B_OPEN
) == B_OK
)
826 fPrefAppSig
.SetTo(buffer
, B_MIME_TYPE_LENGTH
);
829 if (GetSnifferRule(&rule
) == B_OK
)
830 fSniffRule
.CharacterEscape(rule
.String(), "\'", '\\');
834 if (GetFileExtensions(&exts
) == B_OK
) {
836 const char* ext
= NULL
;
837 while (exts
.FindString("extensions", i
++, &ext
) == B_OK
)
838 fExtensions
.insert(pair
<uint32
, BString
>(hash_function(ext
), ext
));
843 if (GetAttrInfo(&attrs
) == B_OK
) {
844 for (int index
= 0; ; index
++) {
845 MimeAttribute
attr(attrs
, index
);
846 if (attr
.InitCheck() != B_OK
)
850 pair
<uint32
, MimeAttribute
>(hash_function(attr
.fName
), attr
));
854 fSmallIcon
= new BBitmap(BRect(0, 0, 15, 15), B_COLOR_8_BIT
);
855 if (GetIcon(fSmallIcon
, B_MINI_ICON
) != B_OK
) {
860 fBigIcon
= new BBitmap(BRect(0, 0, 31, 31), B_COLOR_8_BIT
);
861 if (GetIcon(fBigIcon
, B_LARGE_ICON
) != B_OK
) {
866 if (GetIcon(&fVectorIcon
, &fVectorIconSize
) != B_OK
)
872 MimeType::_UserArgValue(const char* name
)
874 TUserArgsI i
= fUserArguments
.find(hash_function(name
));
875 if (i
== fUserArguments
.end())
878 return i
->second
!= NULL
? i
->second
: "";
883 MimeType::_Dump(const char* mimetype
) throw (Error
)
885 // _Dump can be called as part of all types iteration - so set to required
886 if (Type() == NULL
|| strcasecmp(Type(), mimetype
) != 0)
889 // apps have themself as preferred app - use it to handle
890 // -includeApps option - do not dump applications info
891 if (!fPrefApp
.IsEmpty()
892 && fPrefApp
.ICompare(mimetype
) == 0
893 && _UserArgValue(kIncludeApps
) == NULL
)
896 if (fDumpIcon
&& fSmallIcon
== NULL
&& fBigIcon
== NULL
)
899 if (fDumpRule
&& fSniffRule
.IsEmpty())
902 cout
<< fToolName
<< " -set " << mimetype
;
904 if (fDumpNormal
|| fDumpAll
) {
905 if (!fShort
.IsEmpty())
906 cout
<< " " << kShort
<< " \"" << fShort
<< "\"";
907 if (!fLong
.IsEmpty())
908 cout
<< " " << kLong
<< " \"" << fLong
<< "\"";
909 if (!fPrefApp
.IsEmpty())
910 cout
<< " " << kPreferredApp
<< " " << fPrefApp
;
911 if (!fPrefAppSig
.IsEmpty())
912 cout
<< " " << kPreferredAppSig
<< " " << fPrefAppSig
;
915 if (!fDumpIcon
&& !fSniffRule
.IsEmpty())
916 cout
<< " " << kSniffRule
<< " '" << fSniffRule
<< "'";
918 if (fDumpNormal
|| fDumpAll
)
919 for (map
<uint32
, BString
>::iterator i
= fExtensions
.begin();
920 i
!= fExtensions
.end(); i
++)
921 cout
<< " " << kExtension
<< " " << i
->second
;
924 for (map
<uint32
, MimeAttribute
>::iterator i
= fAttributes
.begin();
925 i
!= fAttributes
.end(); i
++)
928 if (fDumpIcon
|| fDumpAll
) {
929 if (fSmallIcon
!= NULL
&& fSmallIcon
->Bits() != NULL
) {
930 cout
<< " \\" << endl
<< "\t" << kMiniIcon
<< " ";
931 _DumpIcon((uint8
*) fSmallIcon
->Bits(), fSmallIcon
->BitsLength());
934 if (fBigIcon
!= NULL
&& fBigIcon
->Bits() != NULL
) {
935 cout
<< " \\" << endl
<< "\t" << kLargeIcon
<< " ";
936 _DumpIcon((uint8
*) fBigIcon
->Bits(), fBigIcon
->BitsLength());
939 if (fVectorIcon
!= NULL
&& fVectorIconSize
!= 0) {
940 cout
<< " \\" << endl
<< "\t" << kVectorIcon
<< " ";
941 _DumpIcon((uint8
*) fVectorIcon
, fVectorIconSize
);
950 MimeType::_DoEdit() throw (Error
)
952 if (fDoRemove
|| fDoForce
) {
953 status_t result
= Delete();
955 throw Error(strerror(result
), result
);
963 if (!IsInstalled() && Install() != B_OK
)
964 throw Error("could not install mimetype '%s'", Type());
966 const char* value
= _UserArgValue(kShort
);
967 if (value
!= NULL
&& (!fDoAdd
|| fShort
.IsEmpty()))
968 if (SetShortDescription(value
) != B_OK
)
969 throw Error("cannot set %s to %s for '%s'", kShort
, value
, Type());
971 value
= _UserArgValue(kLong
);
972 if (value
!= NULL
&& (!fDoAdd
|| fLong
.IsEmpty()))
973 if (SetLongDescription(value
) != B_OK
)
974 throw Error("cannot set %s to %s for '%s'", kLong
, value
, Type());
976 value
= _UserArgValue(kPreferredApp
);
977 if (value
!= NULL
&& (!fDoAdd
|| fPrefApp
.IsEmpty())) {
979 if (get_ref_for_path(value
, &appHint
) != B_OK
)
980 throw Error("%s ref_entry for '%s' couldn't be found for '%s'",
981 kPreferredApp
, value
, Type());
983 if (SetAppHint(&appHint
) != B_OK
)
984 throw Error("cannot set %s to %s for '%s'",
985 kPreferredApp
, value
, Type());
988 value
= _UserArgValue(kPreferredAppSig
);
989 if (value
!= NULL
&& (!fDoAdd
|| fPrefAppSig
.IsEmpty()))
990 if (SetPreferredApp(value
) != B_OK
)
991 throw Error("cannot set %s to %s for '%s'",
992 kPreferredAppSig
, value
, Type());
994 value
= _UserArgValue(kSniffRule
);
995 if (value
!= NULL
&& (!fDoAdd
|| fSniffRule
.IsEmpty()))
996 if (SetSnifferRule(value
) != B_OK
)
997 throw Error("cannot set %s to %s for '%s'",
998 kSniffRule
, value
, Type());
1000 value
= _UserArgValue(kMiniIcon
);
1001 if (value
!= NULL
&& (!fDoAdd
|| fSmallIcon
== NULL
)) {
1002 int32 iconSize
= strlen(value
);
1003 if (iconSize
/ 2 != B_MINI_ICON
* B_MINI_ICON
)
1004 throw Error("cannot set %s for '%s'. Hex data size %d is invalid",
1005 kMiniIcon
, Type(), iconSize
);
1007 _SetIcon(value
, B_MINI_ICON
);
1010 value
= _UserArgValue(kLargeIcon
);
1011 if (value
!= NULL
&& (!fDoAdd
|| fBigIcon
== NULL
)) {
1012 int32 iconSize
= strlen(value
);
1013 if (iconSize
/ 2 != B_LARGE_ICON
* B_LARGE_ICON
)
1014 throw Error("cannot set %s for '%s'. Hex data size %d is invalid",
1015 kLargeIcon
, Type(), iconSize
);
1017 _SetIcon(value
, B_LARGE_ICON
);
1020 value
= _UserArgValue(kVectorIcon
);
1021 if (value
!= NULL
&& (!fDoAdd
|| fVectorIcon
== NULL
)) {
1022 int32 iconSize
= strlen(value
);
1023 if ((iconSize
% 2) != 0)
1024 throw Error("cannot set %s for '%s'. Hex data size %d is invalid",
1025 kVectorIcon
, Type(), iconSize
);
1027 // vector icon size is negative intended
1028 _SetIcon(value
, -iconSize
);
1031 // handle extensions update
1032 pair
<TUserArgsI
, TUserArgsI
> exts
1033 = fUserArguments
.equal_range(hash_function(kExtension
));
1034 for (TUserArgsI i
= exts
.first
; i
!= exts
.second
; i
++) {
1035 uint32 key
= hash_function(i
->second
);
1036 if (fExtensions
.find(key
) == fExtensions
.end())
1037 fExtensions
.insert(pair
<uint32
, BString
>(key
, i
->second
));
1040 if (exts
.first
!= exts
.second
) {
1042 for (map
<uint32
, BString
>::iterator i
= fExtensions
.begin();
1043 i
!= fExtensions
.end(); i
++)
1044 if (msg
.AddString("extensions", i
->second
.String()) != B_OK
)
1045 throw Error("extension '%s' couldn't be added",
1046 i
->second
.String());
1048 if (SetFileExtensions(&msg
) != B_OK
)
1049 throw Error("set file extensions failed");
1052 // take care about attribute trees
1053 for (TUserAttrsI userAttr
= fUserAttributes
.begin();
1054 userAttr
!= fUserAttributes
.end(); userAttr
++ )
1056 // search for -attribute "name" in args map
1057 TUserArgsI attrArgs
= userAttr
->find(hash_function(kAttribute
));
1058 if (attrArgs
== userAttr
->end())
1059 throw Error("internal error: %s arg not found", kAttribute
);
1061 // check if we already have this attribute cached
1062 map
<uint32
, MimeAttribute
>::iterator
1063 attr
= fAttributes
.find(hash_function(attrArgs
->second
));
1064 if (attr
== fAttributes
.end()) {
1066 MimeAttribute
mimeAttr(*userAttr
);
1068 pair
<uint32
, MimeAttribute
>(hash_function(mimeAttr
.fName
), mimeAttr
));
1070 attr
->second
.SyncWith(*userAttr
);
1073 if (fAttributes
.size() > 0) {
1075 for (map
<uint32
, MimeAttribute
>::iterator i
= fAttributes
.begin();
1076 i
!= fAttributes
.end(); i
++)
1078 i
->second
.StoreInto(&msg
);
1079 if (i
->second
.InitCheck() != B_OK
)
1080 throw Error("storing attributes in message failed");
1083 if (SetAttrInfo(&msg
) != B_OK
)
1084 throw Error("set mimetype attributes failed");
1090 MimeType::Process() throw (Error
)
1092 if (fCheckSniffRule
) {
1093 TUserArgsI I
= fUserArguments
.find(fOpMode
);
1094 if (I
== fUserArguments
.end())
1095 throw Error("Sniffer rule is empty");
1098 status_t result
= BMimeType::CheckSnifferRule(I
->second
, &error
);
1100 cerr
<< I
->second
<< endl
<< "Sniffer rule is correct" << endl
;
1102 cerr
<< error
.String() << endl
;
1107 if (fDoAdd
|| fDoSet
|| fDoForce
|| fDoRemove
) {
1112 if (fDumpNormal
|| fDumpRule
|| fDumpIcon
|| fDumpAll
) {
1113 if (Type() != NULL
) {
1118 BMessage superTypes
;
1119 int32 superCount
= 0;
1120 type_code type
= B_INT32_TYPE
;
1121 if (BMimeType::GetInstalledSupertypes(&superTypes
) != B_OK
1122 || superTypes
.GetInfo("super_types", &type
, &superCount
) != B_OK
)
1123 throw Error("super types enumeration failed");
1125 for (int32 si
= 0; si
< superCount
; si
++) {
1126 const char* superName
= NULL
;
1127 if (superTypes
.FindString("super_types", si
, &superName
) != B_OK
)
1128 throw Error("name for supertype #%d not found", si
);
1131 if (BMimeType::GetInstalledTypes(superName
, &types
) != B_OK
)
1132 throw Error("mimetypes of supertype '%s' not found", superName
);
1135 if (types
.GetInfo("types", &type
, &count
) != B_OK
)
1136 continue; // no sub-types?
1138 for (int32 i
= 0; i
< count
; i
++) {
1139 const char* name
= NULL
;
1140 if (types
.FindString("types", i
, &name
) != B_OK
)
1141 throw Error("name for type %s/#%d not found", superName
, i
);
1151 main(int argc
, char** argv
)
1153 // AppServer link is required to work with bitmaps
1154 BApplication
app("application/x-vnd.haiku.setmime");
1159 throw Error(kNeedArgMessage
);
1161 MimeType
mimetype(argv
);
1165 } catch(exception
& exc
) {
1166 cerr
<< argv
[0] << " : " << exc
.what() << endl
;
1167 cerr
<< kUsageMessage
;