/// <summary>
        /// Serializes the current instance to the passed <paramref name="stream"/>.
        /// </summary>
        /// <param name="stream">The stream where the data will be written to.</param>
        /// <param name="writeData">The action that is being called (when the file header has been written) to now write the actual data.</param>
        /// <param name="autoAlign">A boolean indicating if all component buffers and pack infos should be aligned automatically.</param>
        public void Save(Stream stream, Action <BinaryWriter> writeData, bool autoAlign = true)
        {
            if (!stream.CanWrite || !stream.CanSeek)
            {
                throw new InvalidOperationException("The stream must be writeable and seekable.");
            }

            if (autoAlign)
            {
                var rawBlock = new FamosFileRawBlock();

                this.RawBlocks.Clear();
                this.RawBlocks.Add(rawBlock);

                this.AlignBuffers(rawBlock, FamosFileAlignmentMode.Continuous);
            }

            this.Validate();
            this.BeforeSerialize();

            var codePage = this.LanguageInfo is null ? 1252 : this.LanguageInfo.CodePage;
            var encoding = Encoding.GetEncoding(codePage);

            using (var writer = new BinaryWriter(stream, encoding, leaveOpen: true))
            {
                // Serialize header and leave CK key open.
                this.Serialize(writer);

                // Serialize data.
                writeData.Invoke(writer);

                // Close CK.
                writer.BaseStream.Seek(20, SeekOrigin.Begin);
                writer.Write('1');
            }

            this.AfterSerialize();
        }
Example #2
0
        /// <summary>
        /// Aligns the buffers of all <paramref name="components"/> to the provided <paramref name="rawBlock"/> instance. This is done automatically, if the funcionality is not being disabled during the call to 'famosFile.Save(...)'.
        /// </summary>
        /// <param name="rawBlock">The raw block instance, where the actual data is stored.</param>
        /// <param name="alignmentMode">The buffer alignment mode.</param>
        /// <param name="components">The list of components to align.</param>
        public void AlignBuffers(FamosFileRawBlock rawBlock, FamosFileAlignmentMode alignmentMode, List <FamosFileComponent> components)
        {
            var actualComponents = this.Fields.SelectMany(field => field.Components);

            if (!this.RawBlocks.Contains(rawBlock))
            {
                throw new InvalidOperationException("The passed raw block instance is not a member of this instance.");
            }

            if (!components.Any(component => actualComponents.Contains(component)))
            {
                throw new InvalidOperationException("One or more passed component instances are not a member of this instance.");
            }

            switch (alignmentMode)
            {
            case FamosFileAlignmentMode.Continuous:

                var offset = 0;

                foreach (var component in components)
                {
                    var packInfo = component.PackInfo;
                    var buffer   = packInfo.Buffers.First();

                    packInfo.GroupSize   = 1;
                    packInfo.ByteGapSize = 0;

                    buffer.RawBlock       = rawBlock;
                    buffer.RawBlockOffset = offset;

                    offset += buffer.Length;
                }

                rawBlock.Length = offset;

                break;

            case FamosFileAlignmentMode.Interlaced:

                if (components.Any())
                {
                    var commonSize = components.First().GetSize();

                    if (components.Skip(1).Any(component => component.GetSize() != commonSize))
                    {
                        throw new InvalidOperationException("In interlaced mode, all components must be of the same size.");
                    }
                }
                else
                {
                    return;
                }

                var valueSizes     = components.Select(component => component.PackInfo.ValueSize);
                var totalSize      = valueSizes.Sum();
                var currentOffset  = 0;
                var rawBlockLength = 0L;

                foreach (var component in components)
                {
                    var packInfo = component.PackInfo;
                    var buffer   = packInfo.Buffers.First();

                    packInfo.Offset      = currentOffset;
                    packInfo.GroupSize   = 1;
                    packInfo.ByteGapSize = totalSize - packInfo.ValueSize;

                    buffer.RawBlock       = rawBlock;
                    buffer.RawBlockOffset = 0;

                    currentOffset  += packInfo.ValueSize;
                    rawBlockLength += buffer.Length;
                }

                if (rawBlockLength > Math.Pow(10, 9))
                {
                    throw new InvalidOperationException("In interlaced mode, all buffers are combined into a single large buffer. This buffer would exceed the maximum allowed length of '10^9' bytes.");
                }

                foreach (var component in components)
                {
                    var buffer = component.PackInfo.Buffers.First();
                    buffer.Length        = (int)rawBlockLength;
                    buffer.ConsumedBytes = (int)rawBlockLength;
                }

                rawBlock.Length = rawBlockLength;

                break;

            default:
                throw new InvalidOperationException($"The alignment mode '{alignmentMode}' parameter is unknown.");
            }
        }
Example #3
0
 /// <summary>
 /// Aligns the buffers of all components of this instance to the provided <paramref name="rawBlock"/> instance. This is done automatically, if the funcionality is not being disabled during the call to 'famosFile.Save(...)'.
 /// </summary>
 /// <param name="rawBlock">The raw block instance, where the actual data is stored.</param>
 /// <param name="alignmentMode">The buffer alignment mode.</param>
 public void AlignBuffers(FamosFileRawBlock rawBlock, FamosFileAlignmentMode alignmentMode)
 {
     this.AlignBuffers(rawBlock, alignmentMode, this.Fields.SelectMany(field => field.Components).ToList());
 }