internal void Write()
        {
            var localDiagnostics = new DiagnosticBag();

            ArArchiveFile.UpdateLayout(localDiagnostics);
            if (localDiagnostics.HasErrors)
            {
                throw new ObjectFileException("Invalid ar file", localDiagnostics);
            }
            // Copy for warnings
            localDiagnostics.CopyTo(Diagnostics);

            _startStreamOffset = Stream.Position;

            Stream.Write(ArArchiveFile.Magic);
            Span <byte> entryBuffer = stackalloc byte[ArFile.FileEntrySizeInBytes];

            var headers = ArArchiveFile.LongNamesTable;

            // Serialize all file entries
            for (var i = 0; i < ArArchiveFile.Files.Count; i++)
            {
                var file = ArArchiveFile.Files[i];

                // Serialize the headers at the correct position only if they are required
                if (headers != null && headers.Index == i && headers.Size > 0)
                {
                    WriteFileEntry(entryBuffer, headers);
                    if (Diagnostics.HasErrors)
                    {
                        break;
                    }
                }

                WriteFileEntry(entryBuffer, file);
                if (Diagnostics.HasErrors)
                {
                    break;
                }
            }

            if (Diagnostics.HasErrors)
            {
                throw new ObjectFileException("Unexpected error while writing ar file", Diagnostics);
            }
        }
Example #2
0
        /// <inheritdoc />
        public override bool TryUpdateLayout(DiagnosticBag diagnostics)
        {
            if (diagnostics == null)
            {
                throw new ArgumentNullException(nameof(diagnostics));
            }

            // Check first that we have a valid object file
            var localDiagnostics = new DiagnosticBag();

            Verify(localDiagnostics);

            // If we have any any errors
            if (localDiagnostics.HasErrors)
            {
                localDiagnostics.CopyTo(diagnostics);
                return(false);
            }

            if (Kind == ArArchiveKind.GNU)
            {
                if (LongNamesTable == null)
                {
                    LongNamesTable = new ArLongNamesTable
                    {
                        Parent = this
                    };
                }

                if (SymbolTable != null && SymbolTable.Index == 0)
                {
                    LongNamesTable.Index = 1;
                }
                else
                {
                    LongNamesTable.Index = 1;
                }

                // Reset the calculation of the size of headers
                LongNamesTable.SizeKind = ValueKind.Auto;
            }
            else
            {
                // Don't use headers
                LongNamesTable = null;
            }

            ulong size = (ulong)Magic.Length;

            // Clear the internal names
            foreach (var entry in Files)
            {
                entry.InternalName = null;
            }

            for (var i = 0; i < Files.Count; i++)
            {
                var entry = Files[i];

                // If we have a GNU headers and they are required, add them to the offset and size
                if (LongNamesTable != null && LongNamesTable.Index == i)
                {
                    var headerSize = LongNamesTable.Size;
                    if (headerSize > 0)
                    {
                        LongNamesTable.Offset = size;
                        size += ArFile.FileEntrySizeInBytes + LongNamesTable.Size;
                        if ((size & 1) != 0)
                        {
                            size++;
                        }
                    }
                }

                entry.Offset = size;
                size        += ArFile.FileEntrySizeInBytes + entry.Size;
                if ((size & 1) != 0)
                {
                    size++;
                }
            }

            return(true);
        }