2 * Copyright (c) 2007-2010, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
6 * Ćukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
10 #include "PackageInfo.h"
13 #include <ByteOrder.h>
15 #include <FindDirectory.h>
18 #include <kernel/OS.h>
21 #undef B_TRANSLATION_CONTEXT
22 #define B_TRANSLATION_CONTEXT "PackageInfo"
24 #define RETURN_AND_SET_STATUS(err) fStatus = err; \
25 fprintf(stderr, "err at %s():%d: %x\n", __FUNCTION__, __LINE__, err); \
28 const uint32 kSkipOffset
= 33;
57 B_TIMEX_SINCLAIR_PLATFORM
,
64 PackageInfo::PackageInfo()
68 fDescription(B_TRANSLATE("No package available.")),
75 PackageInfo::PackageInfo(const entry_ref
*ref
)
78 fPackageFile(new BFile(ref
, B_READ_ONLY
)),
79 fDescription(B_TRANSLATE("No package selected.")),
87 PackageInfo::~PackageInfo()
89 pkg_profile
*iter
= 0;
91 iter
= static_cast<pkg_profile
*>(fProfiles
.RemoveItem((int32
)0));
98 PackageItem
*file
= 0;
100 file
= static_cast<PackageItem
*>(fFiles
.RemoveItem((int32
)0));
108 file
= static_cast<PackageScript
*>(fScripts
.RemoveItem((int32
)0));
123 if (!fPackageFile
|| fPackageFile
->InitCheck() != B_OK
) {
124 RETURN_AND_SET_STATUS(B_ERROR
);
127 // Check for the presence of the first AlB tag - as the 'magic number'.
128 // This also ensures that the file header section is present - which
129 // is a crucial pkg section
131 fPackageFile
->Read(buffer
, 8);
132 if (buffer
[0] != 'A' || buffer
[1] != 'l' || buffer
[2] != 'B'
133 || buffer
[3] != 0x1a) {
134 RETURN_AND_SET_STATUS(B_ERROR
);
139 // Parse all known parts of the given .pkg file
143 off_t actualSize
= 0;
144 fPackageFile
->GetSize(&actualSize
);
147 const char padding
[7] = { 0, 0, 0, 0, 0, 0, 0 };
149 platform_type thisPlatform
= B_INVALID_PLATFORM
;
150 cpu_topology_node_info topologyRoot
;
151 uint32 topologyNodeCount
= 1;
152 if (get_cpu_topology_info(&topologyRoot
, &topologyNodeCount
) == B_OK
) {
153 switch (topologyRoot
.data
.root
.platform
) {
155 thisPlatform
= B_AT_CLONE_PLATFORM
;
163 uint64 infoOffset
= 0, groupsOffset
= 0;
166 // Parse the file header
168 bytesRead
= fPackageFile
->Read(buffer
, 7);
169 if (bytesRead
!= 7) {
170 RETURN_AND_SET_STATUS(B_ERROR
);
173 if (!memcmp(buffer
, "PhIn", 5)) {
174 } else if (!memcmp(buffer
, "FVer", 5)) {
175 // Not used right now
176 fPackageFile
->Seek(4, SEEK_CUR
);
177 parser_debug("FVer\n");
178 } else if (!memcmp(buffer
, "AFla", 5)) {
179 // Not used right now TODO: Check what this tag is for
180 fPackageFile
->Seek(8, SEEK_CUR
);
181 parser_debug("AFla\n");
182 } else if (!memcmp(buffer
, "FSiz", 5)) {
183 fPackageFile
->Read(&fileSize
, 8);
184 swap_data(B_UINT64_TYPE
, &fileSize
, sizeof(uint64
),
185 B_SWAP_BENDIAN_TO_HOST
);
186 parser_debug("FSiz %llu\n", fileSize
);
187 } else if (!memcmp(buffer
, "COff", 5)) {
188 fPackageFile
->Read(&infoOffset
, 8);
189 swap_data(B_UINT64_TYPE
, &infoOffset
, sizeof(uint64
),
190 B_SWAP_BENDIAN_TO_HOST
);
191 parser_debug("COff %llu\n", infoOffset
);
192 } else if (!memcmp(buffer
, "AOff", 5)) {
193 fPackageFile
->Read(&groupsOffset
, 8);
194 swap_data(B_UINT64_TYPE
, &groupsOffset
, sizeof(uint64
),
195 B_SWAP_BENDIAN_TO_HOST
);
196 parser_debug("AOff %llu\n", groupsOffset
);
197 } else if (!memcmp(buffer
, padding
, 7)) {
198 // This means the end of this section - we should move to the
201 fPackageFile
->Seek(groupsOffset
, SEEK_SET
);
203 parser_debug("End!\n");
206 RETURN_AND_SET_STATUS(B_ERROR
);
210 fPackageFile
->Read(buffer
, 7);
211 if (memcmp(buffer
, "PkgA", 5) || !groupsOffset
|| !infoOffset
) {
212 RETURN_AND_SET_STATUS(B_ERROR
);
215 // Section header identifying constant byte sequences:
216 const char groupsMarker
[7] = { 0, 0, 0, 1, 0, 0, 4 };
217 const char idMarker
[7] = { 0, 0, 0, 2, 0, 0, 4 };
218 const char pathMarker
[7] = { 0, 0, 0, 3, 0, 0, 4 };
219 const char upathMarker
[7] = { 0, 0, 0, 4, 0, 0, 4 };
220 const char licenseMarker
[7] = { 0, 0, 0, 18, 0, 0, 4 };
221 const char descMarker
[7] = { 0, 0, 0, 5, 0, 0, 2 };
222 const char helpMarker
[7] = { 0, 0, 0, 10, 0, 0, 3 };
224 const char splashScreenMarker
[7] = { 0, 0, 0, 8, 0, 0, 3 };
225 const char disclaimerMarker
[7] = { 0, 0, 0, 7, 0, 0, 3 };
227 const char nameMarker
[7] = { 0, 0, 0, 13, 0, 0, 2 };
228 const char versionMarker
[7] = { 0, 0, 0, 14, 0, 0, 2 };
229 const char devMarker
[7] = { 0, 0, 0, 15, 0, 0, 2 };
230 const char shortDescMarker
[7] = { 0, 0, 0, 17, 0, 0, 2 };
232 int8 section
= P_GROUPS_SECTION
, installDirectoryFlag
= 0;
235 BList
groups(3), userPaths(3), systemPaths(10);
236 bool groupStarted
= false;
237 parser_debug("Package Info reached!\n");
238 // TODO: Maybe checking whether the needed number of bytes are read
239 // everytime would be a good idea
241 // Parse the package info section
243 bytesRead
= fPackageFile
->Read(buffer
, 7);
244 if (bytesRead
!= 7) {
245 parser_debug("EOF!\n");
249 if (!memcmp(buffer
, groupsMarker
, 7)) {
250 section
= P_GROUPS_SECTION
;
251 parser_debug("Got to Groups section\n");
253 } else if (!memcmp(buffer
, pathMarker
, 7)) {
254 section
= P_PATH_SECTION
;
255 parser_debug("Got to System Paths\n");
257 } else if (!memcmp(buffer
, upathMarker
, 7)) {
258 section
= P_USER_PATH_SECTION
;
259 parser_debug("Got to User Paths\n");
261 } else if (!memcmp(buffer
, licenseMarker
, 7)) {
262 section
= P_LICENSE_SECTION
;
263 parser_debug("Got to License\n");
265 // After this, non sectioned tags follow
266 } else if (!memcmp(buffer
, disclaimerMarker
, 7)) {
268 fPackageFile
->Read(&length
, 8);
269 swap_data(B_UINT64_TYPE
, &length
, sizeof(uint64
),
270 B_SWAP_BENDIAN_TO_HOST
);
273 if (fPackageFile
->Read(&original
, 8) != 8) {
274 RETURN_AND_SET_STATUS(B_ERROR
);
276 swap_data(B_UINT64_TYPE
, &original
, sizeof(uint64
),
277 B_SWAP_BENDIAN_TO_HOST
);
279 fPackageFile
->Seek(4, SEEK_CUR
);
281 uint8
*compressed
= new uint8
[length
];
282 if (fPackageFile
->Read(compressed
, length
)
283 != static_cast<int64
>(length
)) {
285 RETURN_AND_SET_STATUS(B_ERROR
);
288 uint8
*disclaimer
= new uint8
[original
+ 1];
289 status_t ret
= inflate_data(compressed
, length
, disclaimer
,
291 disclaimer
[original
] = 0;
295 RETURN_AND_SET_STATUS(B_ERROR
);
298 fDisclaimer
= (char *)disclaimer
;
302 } else if (!memcmp(buffer
, splashScreenMarker
, 7)) {
304 fPackageFile
->Read(&length
, 8);
305 swap_data(B_UINT64_TYPE
, &length
, sizeof(uint64
),
306 B_SWAP_BENDIAN_TO_HOST
);
309 if (fPackageFile
->Read(&original
, 8) != 8) {
310 RETURN_AND_SET_STATUS(B_ERROR
);
312 swap_data(B_UINT64_TYPE
, &original
, sizeof(uint64
),
313 B_SWAP_BENDIAN_TO_HOST
);
315 fPackageFile
->Seek(4, SEEK_CUR
);
317 uint8
*compressed
= new uint8
[length
];
318 if (fPackageFile
->Read(compressed
, length
)
319 != static_cast<int64
>(length
)) {
321 RETURN_AND_SET_STATUS(B_ERROR
);
324 fImage
.SetSize(original
);
325 status_t ret
= inflate_data(compressed
, length
,
326 static_cast<uint8
*>(const_cast<void *>(fImage
.Buffer())),
330 RETURN_AND_SET_STATUS(B_ERROR
);
339 if (!memcmp(buffer
, "DPat", 5)) {
340 parser_debug("DPat\n");
342 } else if (!memcmp(buffer
, "FDst", 5)) {
343 parser_debug("FDst - ");
345 if (fPackageFile
->Read(&dir
, 4) != 4) {
346 RETURN_AND_SET_STATUS(B_ERROR
);
348 swap_data(B_UINT32_TYPE
, &dir
, sizeof(uint32
),
349 B_SWAP_BENDIAN_TO_HOST
);
350 BPath
*path
= new BPath();
351 status_t ret
= find_directory(dir
, path
);
354 RETURN_AND_SET_STATUS(B_ERROR
);
357 parser_debug("%s\n", path
->Path());
359 systemPaths
.AddItem(path
);
360 } else if (!memcmp(buffer
, "PaNa", 5)) {
361 parser_debug("PaNa\n");
362 if (fPackageFile
->Read(&length
, 4) != 4) {
363 RETURN_AND_SET_STATUS(B_ERROR
);
365 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
366 B_SWAP_BENDIAN_TO_HOST
);
367 // Since its a default, system path, we can ignore the path
368 // name - all information needed is beside the FDst tag.
369 fPackageFile
->Seek(length
, SEEK_CUR
);
370 } else if (!memcmp(buffer
, padding
, 7)) {
371 parser_debug("Padding!\n");
374 RETURN_AND_SET_STATUS(B_ERROR
);
379 case P_GROUPS_SECTION
:
381 if (!memcmp(buffer
, "IGrp", 5)) {
382 // Creata a new group
384 group
= pkg_profile();
385 parser_debug("IGrp\n");
386 } else if (!memcmp(buffer
, "GrpN", 5)) {
388 RETURN_AND_SET_STATUS(B_ERROR
);
391 parser_debug("GrpN\n");
392 fPackageFile
->Read(&length
, 4);
393 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
394 B_SWAP_BENDIAN_TO_HOST
);
396 char *name
= new char[length
+ 1];
397 fPackageFile
->Read(name
, length
);
401 } else if (!memcmp(buffer
, "GrpD", 5)) {
403 RETURN_AND_SET_STATUS(B_ERROR
);
406 parser_debug("GrpD\n");
407 fPackageFile
->Read(&length
, 4);
408 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
409 B_SWAP_BENDIAN_TO_HOST
);
411 char *desc
= new char[length
+ 1];
412 fPackageFile
->Read(desc
, length
);
414 group
.description
= desc
;
416 } else if (!memcmp(buffer
, "GrHt", 5)) {
418 RETURN_AND_SET_STATUS(B_ERROR
);
421 parser_debug("GrHt\n");
422 // For now, we don't need group help
423 fPackageFile
->Read(&length
, 4);
424 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
425 B_SWAP_BENDIAN_TO_HOST
);
426 fPackageFile
->Seek(length
, SEEK_CUR
);
427 } else if (!memcmp(buffer
, padding
, 5)) {
429 parser_debug("No group - padding!\n");
433 fProfiles
.AddItem(new pkg_profile(group
));
434 parser_debug("Group added: %s %s\n", group
.name
.String(),
435 group
.description
.String());
437 groupStarted
= false;
438 } else if (!memcmp(buffer
, "GrId", 5)) {
440 fPackageFile
->Read(&id
, 4);
441 swap_data(B_UINT32_TYPE
, &id
, sizeof(uint32
),
442 B_SWAP_BENDIAN_TO_HOST
);
444 parser_debug("GrId\n");
446 if (id
== 0xffffffff)
447 groups
.AddItem(NULL
);
449 groups
.AddItem(fProfiles
.ItemAt(id
));
450 } else if (!memcmp(buffer
, idMarker
, 7)
451 || !memcmp(buffer
, groupsMarker
, 7)) {
452 parser_debug("Marker, jumping!\n");
455 RETURN_AND_SET_STATUS(B_ERROR
);
460 case P_LICENSE_SECTION
:
462 if (!memcmp(buffer
, "Lic?", 5)) {
463 parser_debug("Lic?\n");
464 // This tag informs whether a license is present in the
465 // package or not. Since we don't care about licenses right
466 // now, just skip this section
467 fPackageFile
->Seek(4, SEEK_CUR
);
468 } else if (!memcmp(buffer
, "LicP", 5)) {
469 parser_debug("LicP\n");
470 fPackageFile
->Read(&length
, 4);
471 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
472 B_SWAP_BENDIAN_TO_HOST
);
474 fPackageFile
->Seek(length
, SEEK_CUR
);
475 } else if (!memcmp(buffer
, padding
, 7)) {
477 } else if (!memcmp(buffer
, descMarker
, 7)) {
478 parser_debug("Description text reached\n");
479 fPackageFile
->Read(&length
, 4);
480 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
481 B_SWAP_BENDIAN_TO_HOST
);
483 char *description
= new char[length
+ 1];
484 fPackageFile
->Read(description
, length
);
485 description
[length
] = 0;
486 fDescription
= description
;
488 // Truncate all leading newlines
489 for (i
= 0; i
< length
; i
++) {
490 if (fDescription
[i
] != '\n')
493 fDescription
.Remove(0, i
);
495 delete[] description
;
496 parser_debug("Description text reached\n");
498 // After this, there's a known size sequence of bytes, which
499 // meaning is yet to be determined.
501 // One is already known. The byte (or just its least
502 // significant bit) at offset 21 from the description text
503 // is responsible for the install folder existence
504 // information. If it is 0, there is no install folder, if
505 // it is 1 (or the least significant bit is set) it means
506 // we should install all 0xffffffff files/directories to
507 // the first directory existing in the package
508 fPackageFile
->Seek(21, SEEK_CUR
);
509 if (fPackageFile
->Read(&installDirectoryFlag
, 1) != 1) {
510 RETURN_AND_SET_STATUS(B_ERROR
);
513 fPackageFile
->Seek(11, SEEK_CUR
);
514 } else if (!memcmp(buffer
, nameMarker
, 7)) {
515 parser_debug("Package name reached\n");
516 fPackageFile
->Read(&length
, 4);
517 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
518 B_SWAP_BENDIAN_TO_HOST
);
520 char *name
= new char[length
+ 1];
521 fPackageFile
->Read(name
, length
);
525 } else if (!memcmp(buffer
, versionMarker
, 7)) {
526 parser_debug("Package version reached\n");
527 fPackageFile
->Read(&length
, 4);
528 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
529 B_SWAP_BENDIAN_TO_HOST
);
531 char *version
= new char[length
+ 1];
532 fPackageFile
->Read(version
, length
);
536 } else if (!memcmp(buffer
, devMarker
, 7)) {
537 parser_debug("Package developer reached\n");
538 fPackageFile
->Read(&length
, 4);
539 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
540 B_SWAP_BENDIAN_TO_HOST
);
542 char *dev
= new char[length
+ 1];
543 fPackageFile
->Read(dev
, length
);
547 } else if (!memcmp(buffer
, shortDescMarker
, 7)) {
548 parser_debug("Package short description reached\n");
549 fPackageFile
->Read(&length
, 4);
550 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
551 B_SWAP_BENDIAN_TO_HOST
);
553 char *desc
= new char[length
+ 1];
554 fPackageFile
->Read(desc
, length
);
558 } else if (!memcmp(buffer
, helpMarker
, 7)) {
559 // The help text is a stored in deflated state, preceded by a 64 bit
560 // compressed size, 64 bit inflated size and a 32 bit integer
561 // Since there was no discussion whether we need this help text,
562 // it will be skipped
563 parser_debug("Help text reached\n");
565 fPackageFile
->Read(&length
, 8);
566 swap_data(B_UINT64_TYPE
, &length
, sizeof(uint64
),
567 B_SWAP_BENDIAN_TO_HOST
);
569 fPackageFile
->Seek(12 + length
, SEEK_CUR
);
574 case P_USER_PATH_SECTION
:
576 if (!memcmp(buffer
, "DPat", 5)) {
577 parser_debug("DPat\n");
579 } else if (!memcmp(buffer
, "DQue", 5)) {
580 parser_debug("DQue\n");
582 } else if (!memcmp(buffer
, "DQTi", 5)) {
583 parser_debug("DQTi\n");
585 if (fPackageFile
->Read(&length
, 4) != 4) {
586 RETURN_AND_SET_STATUS(B_ERROR
);
588 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
589 B_SWAP_BENDIAN_TO_HOST
);
590 char *ti
= new char[length
+ 1];
591 fPackageFile
->Read(ti
, length
);
593 parser_debug("DQTi - %s\n", ti
);
595 } else if (!memcmp(buffer
, "DQSz", 5)) {
596 parser_debug("DQSz\n");
598 if (fPackageFile
->Read(&size
, 8) != 8) {
599 RETURN_AND_SET_STATUS(B_ERROR
);
601 swap_data(B_UINT64_TYPE
, &size
, sizeof(uint64
),
602 B_SWAP_BENDIAN_TO_HOST
);
603 parser_debug("DQSz - %Ld\n", size
);
604 } else if (!memcmp(buffer
, "DQMi", 5)) {
605 // TODO actually check if the query finds a file with
606 // size found previously
607 parser_debug("DQMi\n");
609 if (fPackageFile
->Read(&length
, 4) != 4) {
610 RETURN_AND_SET_STATUS(B_ERROR
);
612 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
613 B_SWAP_BENDIAN_TO_HOST
);
614 char *signature
= new char[length
+ 1];
615 fPackageFile
->Read(signature
, length
);
616 signature
[length
] = 0;
617 parser_debug("DQMi - %s\n", signature
);
619 } else if (!memcmp(buffer
, "PaNa", 5)) {
620 parser_debug("PaNa\n");
621 fPackageFile
->Read(&length
, 4);
622 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
623 B_SWAP_BENDIAN_TO_HOST
);
625 char *pathname
= new char[length
+ 1];
626 fPackageFile
->Read(pathname
, length
);
627 pathname
[length
] = 0;
628 BString
*path
= new BString(pathname
);
629 if (length
> 0 && pathname
[length
- 1] == '/')
630 path
->Remove(length
- 1, 1);
631 userPaths
.AddItem(path
);
633 } else if (!memcmp(buffer
, padding
, 7)) {
634 parser_debug("Padding!\n");
637 parser_debug("Unknown user path section %s\n", buffer
);
638 RETURN_AND_SET_STATUS(B_ERROR
);
645 BString nameString
, mimeString
, signatureString
, linkString
;
646 BString itemPath
= "", installDirectory
= "";
647 uint32 directoryCount
= 0;
649 uint8 element
= P_NONE
;
650 uint32 itemGroups
= 0, path
= 0, cust
= 0, ctime
= 0, mtime
= 0;
651 uint32 platform
= 0xffffffff;
652 uint64 offset
= 0, size
= 0, originalSize
= 0, mode
= 0;
653 uint8 pathType
= P_INSTALL_PATH
;
656 fPackageFile
->Seek(infoOffset
, SEEK_SET
);
658 // Parse package file data
660 bytesRead
= fPackageFile
->Read(buffer
, 7);
661 if (bytesRead
!= 7) {
662 RETURN_AND_SET_STATUS(B_ERROR
);
665 #define INIT_VARS(tag, type) \
666 parser_debug(tag "\n"); \
671 signatureString = ""; \
678 platform = 0xffffffff; \
682 if (!memcmp(buffer
, "FilI", 5)) {
683 INIT_VARS("FilI", P_FILE
);
684 } else if (!memcmp(buffer
, "FldI", 5)) {
685 INIT_VARS("FldI", P_DIRECTORY
);
686 } else if (!memcmp(buffer
, "LnkI", 5)) {
687 INIT_VARS("LnkI", P_LINK
);
688 } else if (!memcmp(buffer
, "ScrI", 5)) {
689 INIT_VARS("ScrI", P_SCRIPT
);
690 } else if (!memcmp(buffer
, "Name", 5)) {
691 if (element
== P_NONE
) {
692 RETURN_AND_SET_STATUS(B_ERROR
);
695 parser_debug("Name\n");
696 fPackageFile
->Read(&length
, 4);
697 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
698 B_SWAP_BENDIAN_TO_HOST
);
700 char *name
= new char[length
+ 1];
701 fPackageFile
->Read(name
, length
);
706 } else if (!memcmp(buffer
, "Grps", 5)) {
707 if (element
== P_NONE
) {
708 RETURN_AND_SET_STATUS(B_ERROR
);
711 parser_debug("Grps\n");
712 fPackageFile
->Read(&itemGroups
, 4);
713 swap_data(B_UINT32_TYPE
, &itemGroups
, sizeof(uint32
),
714 B_SWAP_BENDIAN_TO_HOST
);
715 } else if (!memcmp(buffer
, "Dest", 5)) {
716 if (element
== P_NONE
) {
717 RETURN_AND_SET_STATUS(B_ERROR
);
720 parser_debug("Dest\n");
721 fPackageFile
->Read(&path
, 4);
722 swap_data(B_UINT32_TYPE
, &path
, sizeof(uint32
),
723 B_SWAP_BENDIAN_TO_HOST
);
724 } else if (!memcmp(buffer
, "Cust", 5)) {
725 if (element
== P_NONE
) {
726 RETURN_AND_SET_STATUS(B_ERROR
);
729 parser_debug("Cust\n");
730 fPackageFile
->Read(&cust
, 4);
731 swap_data(B_UINT32_TYPE
, &cust
, sizeof(uint32
),
732 B_SWAP_BENDIAN_TO_HOST
);
733 } else if (!memcmp(buffer
, "Repl", 5)) {
734 if (element
== P_NONE
) {
735 RETURN_AND_SET_STATUS(B_ERROR
);
738 parser_debug("Repl\n");
739 fPackageFile
->Seek(4, SEEK_CUR
);
740 // TODO: Should the replace philosophy depend on this flag? For now
741 // I always leave the decision to the user
742 } else if (!memcmp(buffer
, "Plat", 5)) {
743 if (element
== P_NONE
) {
744 RETURN_AND_SET_STATUS(B_ERROR
);
747 parser_debug("Plat\n");
748 fPackageFile
->Read(&platform
, 4);
749 swap_data(B_UINT32_TYPE
, &platform
, sizeof(uint32
),
750 B_SWAP_BENDIAN_TO_HOST
);
751 } else if (!memcmp(buffer
, "CTim", 5)) {
752 if (element
== P_NONE
) {
753 RETURN_AND_SET_STATUS(B_ERROR
);
756 parser_debug("CTim\n");
757 fPackageFile
->Read(&ctime
, 4);
758 swap_data(B_UINT32_TYPE
, &ctime
, sizeof(uint32
),
759 B_SWAP_BENDIAN_TO_HOST
);
760 } else if (!memcmp(buffer
, "MTim", 5)) {
761 if (element
== P_NONE
) {
762 RETURN_AND_SET_STATUS(B_ERROR
);
765 parser_debug("MTim\n");
766 fPackageFile
->Read(&mtime
, 4);
767 swap_data(B_UINT32_TYPE
, &mtime
, sizeof(uint32
),
768 B_SWAP_BENDIAN_TO_HOST
);
769 } else if (!memcmp(buffer
, "OffT", 5)) {
770 if (element
== P_NONE
) {
771 RETURN_AND_SET_STATUS(B_ERROR
);
774 parser_debug("OffT\n");
775 fPackageFile
->Read(&offset
, 8);
776 swap_data(B_UINT64_TYPE
, &offset
, sizeof(uint64
),
777 B_SWAP_BENDIAN_TO_HOST
);
778 } else if (!memcmp(buffer
, "Mime", 5)) {
779 if (element
!= P_FILE
) {
780 RETURN_AND_SET_STATUS(B_ERROR
);
783 fPackageFile
->Read(&length
, 4);
784 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
785 B_SWAP_BENDIAN_TO_HOST
);
787 char *mime
= new char[length
+ 1];
788 fPackageFile
->Read(mime
, length
);
790 parser_debug("Mime: %s\n", mime
);
794 } else if (!memcmp(buffer
, "CmpS", 5)) {
795 if (element
== P_NONE
) {
796 RETURN_AND_SET_STATUS(B_ERROR
);
799 parser_debug("CmpS\n");
800 fPackageFile
->Read(&size
, 8);
801 swap_data(B_UINT64_TYPE
, &size
, sizeof(uint64
),
802 B_SWAP_BENDIAN_TO_HOST
);
803 } else if (!memcmp(buffer
, "OrgS", 5)) {
804 if (element
!= P_FILE
&& element
!= P_LINK
&& element
!= P_SCRIPT
) {
805 RETURN_AND_SET_STATUS(B_ERROR
);
808 parser_debug("OrgS\n");
809 fPackageFile
->Read(&originalSize
, 8);
810 swap_data(B_UINT64_TYPE
, &originalSize
, sizeof(uint64
),
811 B_SWAP_BENDIAN_TO_HOST
);
812 } else if (!memcmp(buffer
, "VrsI", 5)) {
813 if (element
!= P_FILE
) {
814 RETURN_AND_SET_STATUS(B_ERROR
);
817 parser_debug("VrsI\n");
818 fPackageFile
->Seek(24, SEEK_CUR
);
820 // Also, check what those empty 20 bytes mean
821 } else if (!memcmp(buffer
, "Mode", 5)) {
822 if (element
!= P_FILE
&& element
!= P_LINK
) {
823 RETURN_AND_SET_STATUS(B_ERROR
);
826 parser_debug("Mode\n");
827 fPackageFile
->Read(&mode
, 4);
828 swap_data(B_UINT32_TYPE
, &mode
, sizeof(uint32
),
829 B_SWAP_BENDIAN_TO_HOST
);
830 } else if (!memcmp(buffer
, "FDat", 5)) {
831 if (element
!= P_DIRECTORY
) {
832 RETURN_AND_SET_STATUS(B_ERROR
);
835 parser_debug("FDat\n");
836 } else if (!memcmp(buffer
, "ASig", 5)) {
837 if (element
!= P_FILE
) {
838 RETURN_AND_SET_STATUS(B_ERROR
);
841 fPackageFile
->Read(&length
, 4);
842 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
843 B_SWAP_BENDIAN_TO_HOST
);
845 char *signature
= new char[length
+ 1];
846 fPackageFile
->Read(signature
, length
);
847 signature
[length
] = 0;
848 parser_debug("Signature: %s\n", signature
);
850 signatureString
= signature
;
852 } else if (!memcmp(buffer
, "Link", 5)) {
853 if (element
!= P_LINK
) {
854 RETURN_AND_SET_STATUS(B_ERROR
);
857 fPackageFile
->Read(&length
, 4);
858 swap_data(B_UINT32_TYPE
, &length
, sizeof(uint32
),
859 B_SWAP_BENDIAN_TO_HOST
);
861 char *link
= new char[length
+ 1];
862 fPackageFile
->Read(link
, length
);
864 parser_debug("Link: %s\n", link
);
868 } else if (!memcmp(buffer
, padding
, 7)) {
869 PackageItem
*item
= NULL
;
871 parser_debug("Padding!\n");
872 if (platform
!= 0xffffffff
873 && static_cast<platform_type
>(platform
) != thisPlatform
) {
874 // If the file/directory/item's platform is different than the
875 // target platform (or different than the 'any' constant),
877 } else if (element
== P_FILE
) {
878 if (itemGroups
&& offset
&& size
) {
880 uint8 localType
= pathType
;
882 if (path
== 0xfffffffe)
883 dest
<< itemPath
<< "/" << nameString
.String();
884 else if (path
== 0xffffffff) {
885 localType
= P_INSTALL_PATH
;
886 dest
= installDirectory
;
890 BString
*def
= static_cast<BString
*>(
891 userPaths
.ItemAt(path
));
893 RETURN_AND_SET_STATUS(B_ERROR
);
895 if ((*def
)[0] == '/')
896 localType
= P_SYSTEM_PATH
;
898 localType
= P_USER_PATH
;
900 dest
<< *def
<< "/" << nameString
;
902 BPath
*def
= static_cast<BPath
*>(
903 systemPaths
.ItemAt(path
));
905 RETURN_AND_SET_STATUS(B_ERROR
);
907 localType
= P_SYSTEM_PATH
;
909 dest
<< def
->Path() << "/" << nameString
;
913 parser_debug("Adding file: %s!\n", dest
.String());
915 item
= new PackageFile(fPackageFile
, dest
, localType
, ctime
,
916 mtime
, offset
, size
, originalSize
, 0, mimeString
,
917 signatureString
, mode
);
919 } else if (element
== P_DIRECTORY
) {
921 if (installDirectoryFlag
!= 0) {
922 if (installDirectoryFlag
< 0) {
924 if (path
== 0xfffffffe) {
925 // Install to current directory
926 itemPath
<< "/" << nameString
.String();
928 } else if (path
== 0xffffffff) {
929 // Install to install directory
930 pathType
= P_INSTALL_PATH
;
931 itemPath
= installDirectory
;
932 itemPath
<< nameString
;
935 // Install to defined directory
937 BString
*def
= static_cast<BString
*>(
938 userPaths
.ItemAt(path
));
940 RETURN_AND_SET_STATUS(B_ERROR
);
942 if ((*def
)[0] == '/')
943 pathType
= P_SYSTEM_PATH
;
945 pathType
= P_USER_PATH
;
949 BPath
*def
= static_cast<BPath
*>(
950 systemPaths
.ItemAt(path
));
952 RETURN_AND_SET_STATUS(B_ERROR
);
954 pathType
= P_SYSTEM_PATH
;
956 itemPath
= def
->Path();
959 itemPath
<< "/" << nameString
;
964 if (path
!= 0xffffffff) {
965 RETURN_AND_SET_STATUS(B_ERROR
);
968 installDirectory
= nameString
;
969 installDirectory
<< "/";
970 pathType
= P_INSTALL_PATH
;
971 itemPath
= nameString
;
973 installDirectoryFlag
= -1;
976 parser_debug("Adding the directory %s!\n",
979 item
= new PackageDirectory(fPackageFile
, itemPath
,
980 pathType
, ctime
, mtime
, offset
, size
);
982 installDirectoryFlag
= -1;
984 } else if (element
== P_LINK
) {
985 if (itemGroups
&& linkString
.Length()) {
987 uint8 localType
= pathType
;
989 if (path
== 0xfffffffe)
990 dest
<< itemPath
<< "/" << nameString
.String();
991 else if (path
== 0xffffffff) {
992 localType
= P_INSTALL_PATH
;
993 dest
= installDirectory
;
997 BString
*def
= static_cast<BString
*>(
998 userPaths
.ItemAt(path
));
1000 RETURN_AND_SET_STATUS(B_ERROR
);
1002 if ((*def
)[0] == '/')
1003 localType
= P_SYSTEM_PATH
;
1005 localType
= P_USER_PATH
;
1007 dest
<< *def
<< "/" << nameString
;
1009 BPath
*def
= static_cast<BPath
*>(systemPaths
.ItemAt(path
));
1011 RETURN_AND_SET_STATUS(B_ERROR
);
1013 localType
= P_SYSTEM_PATH
;
1015 dest
<< def
->Path() << "/" << nameString
;
1019 parser_debug("Adding link: %s! (type %s)\n", dest
.String(),
1020 pathType
== P_SYSTEM_PATH
1021 ? "System" : localType
== P_INSTALL_PATH
1022 ? "Install" : "User");
1024 item
= new PackageLink(fPackageFile
, dest
, linkString
,
1025 localType
, ctime
, mtime
, mode
, offset
, size
);
1027 } else if (element
== P_SCRIPT
) {
1028 parser_debug("Adding the script %s!\n",
1029 nameString
.String());
1031 BString workingDirectory
;
1032 uint8 localType
= P_SYSTEM_PATH
;
1034 workingDirectory
<< itemPath
;
1035 else if (path
== 0xffffffff) {
1036 workingDirectory
<< installDirectory
;
1037 localType
= P_INSTALL_PATH
;
1040 fScripts
.AddItem(new PackageScript(fPackageFile
,
1041 workingDirectory
, localType
, offset
, size
, originalSize
));
1043 // If the directory tree count is equal to zero, this means all
1044 // directory trees have been closed and a padding sequence means the
1045 // end of the section
1046 if (directoryCount
== 0)
1048 ret
= itemPath
.FindLast('/');
1049 if (ret
== B_ERROR
) {
1053 itemPath
.Truncate(ret
);
1059 _AddItem(item
, originalSize
, itemGroups
, path
, cust
);
1063 } else if (!memcmp(buffer
, "PkgA", 5)) {
1064 parser_debug("PkgA\n");
1066 } else if (!memcmp(buffer
, "PtcI", 5)) {
1067 parser_debug("PtcI\n");
1070 fprintf(stderr
, "Unknown file tag %s\n", buffer
);
1071 RETURN_AND_SET_STATUS(B_ERROR
);
1075 if (static_cast<uint64
>(actualSize
) != fileSize
) {
1076 // Inform the user of a possible error
1078 BAlert
*warning
= new BAlert("filesize_wrong",
1079 B_TRANSLATE("There seems to be a file size mismatch in the "
1080 "package file. The package might be corrupted or have been "
1081 "modified after its creation. Do you still wish to continue?"),
1082 B_TRANSLATE("Continue"),
1083 B_TRANSLATE("Abort"), NULL
,
1084 B_WIDTH_AS_USUAL
, B_WARNING_ALERT
);
1085 warning
->SetShortcut(1, B_ESCAPE
);
1086 selection
= warning
->Go();
1088 if (selection
== 1) {
1089 RETURN_AND_SET_STATUS(B_ERROR
);
1093 if (!groups
.IsEmpty())
1101 PackageInfo::_AddItem(PackageItem
*item
, uint64 size
, uint32 groups
,
1102 uint32 path
, uint32 cust
)
1104 // Add the item to all groups it resides in
1105 uint32 i
, n
= fProfiles
.CountItems(), mask
= 1;
1106 pkg_profile
*profile
;
1108 fFiles
.AddItem(item
);
1110 for (i
= 0;i
< n
;i
++) {
1111 if (groups
& mask
) {
1112 profile
= static_cast<pkg_profile
*>(fProfiles
.ItemAt(i
));
1113 profile
->items
.AddItem(item
);
1114 profile
->space_needed
+= size
;
1115 // If there is at least one non-predefined destination element
1116 // in the package, we give the user the ability to select the
1117 // installation directory.
1118 // If there are only predefined path files in the package, but
1119 // such defined by the user, the user will be able to select
1120 // the destination volume
1121 if (path
== 0xffffffff)
1122 profile
->path_type
= P_INSTALL_PATH
;
1123 else if (path
< 0xfffffffe &&
1124 profile
->path_type
!= P_INSTALL_PATH
) {
1126 profile
->path_type
= P_USER_PATH
;