コード例 #1
0
ファイル: BlubbZipFile.cs プロジェクト: GodLesZ/svn-dump
		void CopyEntryDirect( BlubbZipFile workFile, BlubbUpdate update, ref long destinationPosition ) {
			bool skipOver = false;
			if( update.Entry.Offset == destinationPosition ) {
				skipOver = true;
			}

			if( !skipOver ) {
				baseStream_.Position = destinationPosition;
				workFile.WriteLocalEntryHeader( update );
				destinationPosition = baseStream_.Position;
			}

			long sourcePosition = 0;

			const int NameLengthOffset = 26;

			// TODO: Add base for SFX friendly handling
			long entryDataOffset = update.Entry.Offset + NameLengthOffset;

			baseStream_.Seek( entryDataOffset, SeekOrigin.Begin );

			// Clumsy way of handling retrieving the original name and extra data length for now.
			// TODO: Stop re-reading name and data length in CopyEntryDirect.
			uint nameLength = ReadLEUshort();
			uint extraLength = ReadLEUshort();

			sourcePosition = baseStream_.Position + nameLength + extraLength;

			if( skipOver ) {
				destinationPosition +=
					( sourcePosition - entryDataOffset ) + NameLengthOffset +	// Header size
					update.Entry.CompressedSize + GetDescriptorSize( update );
			} else {
				if( update.Entry.CompressedSize > 0 ) {
					CopyEntryDataDirect( update, baseStream_, false, ref destinationPosition, ref sourcePosition );
				}
				CopyDescriptorBytesDirect( update, baseStream_, ref destinationPosition, sourcePosition );
			}
		}
コード例 #2
0
ファイル: BlubbZipFile.cs プロジェクト: GodLesZ/svn-dump
		void CopyEntry( BlubbZipFile workFile, BlubbUpdate update ) {
			workFile.WriteLocalEntryHeader( update );

			if( update.Entry.CompressedSize > 0 ) {
				const int NameLengthOffset = 26;

				long entryDataOffset = update.Entry.Offset + NameLengthOffset;

				// TODO: This wont work for SFX files!
				baseStream_.Seek( entryDataOffset, SeekOrigin.Begin );

				uint nameLength = ReadLEUshort();
				uint extraLength = ReadLEUshort();

				baseStream_.Seek( nameLength + extraLength, SeekOrigin.Current );

				CopyBytes( update, workFile.baseStream_, baseStream_, update.Entry.CompressedSize, false );
			}
			CopyDescriptorBytes( update, workFile.baseStream_, baseStream_ );
		}
コード例 #3
0
ファイル: BlubbZipFile.cs プロジェクト: GodLesZ/svn-dump
		void AddEntry( BlubbZipFile workFile, BlubbUpdate update ) {
			Stream source = null;

			if( update.Entry.IsFile ) {
				source = update.GetSource();

				if( source == null ) {
					source = updateDataSource_.GetSource( update.Entry, update.Filename );
				}
			}

			if( source != null ) {
				using( source ) {
					long sourceStreamLength = source.Length;
					if( update.OutEntry.Size < 0 ) {
						update.OutEntry.Size = sourceStreamLength;
					} else {
						// Check for errant entries.
						if( update.OutEntry.Size != sourceStreamLength ) {
							throw new BlubbZipException( "Entry size/stream size mismatch" );
						}
					}

					workFile.WriteLocalEntryHeader( update );

					long dataStart = workFile.baseStream_.Position;

					using( Stream output = workFile.GetOutputStream( update.OutEntry ) ) {
						CopyBytes( update, output, source, sourceStreamLength, true );
					}

					long dataEnd = workFile.baseStream_.Position;
					update.OutEntry.CompressedSize = dataEnd - dataStart;

					if( ( update.OutEntry.Flags & (int)GeneralBitFlags.Descriptor ) == (int)GeneralBitFlags.Descriptor ) {
						BlubbZipHelperStream helper = new BlubbZipHelperStream( workFile.baseStream_ );
						helper.WriteDataDescriptor( update.OutEntry );
					}
				}
			} else {
				workFile.WriteLocalEntryHeader( update );
				update.OutEntry.CompressedSize = 0;
			}

		}
コード例 #4
0
ファイル: BlubbZipFile.cs プロジェクト: GodLesZ/svn-dump
		void ModifyEntry( BlubbZipFile workFile, BlubbUpdate update ) {
			workFile.WriteLocalEntryHeader( update );
			long dataStart = workFile.baseStream_.Position;

			// TODO: This is slow if the changes don't effect the data!!
			if( update.Entry.IsFile && ( update.Filename != null ) ) {
				using( Stream output = workFile.GetOutputStream( update.OutEntry ) ) {
					using( Stream source = this.GetInputStream( update.Entry ) ) {
						CopyBytes( update, output, source, source.Length, true );
					}
				}
			}

			long dataEnd = workFile.baseStream_.Position;
			update.Entry.CompressedSize = dataEnd - dataStart;
		}
コード例 #5
0
ファイル: BlubbZipFile.cs プロジェクト: GodLesZ/svn-dump
		void CopyDescriptorBytesDirect( BlubbUpdate update, Stream stream, ref long destinationPosition, long sourcePosition ) {
			int bytesToCopy = GetDescriptorSize( update );

			while( bytesToCopy > 0 ) {
				int readSize = (int)bytesToCopy;
				byte[] buffer = GetBuffer();

				stream.Position = sourcePosition;
				int bytesRead = stream.Read( buffer, 0, readSize );
				if( bytesRead > 0 ) {
					stream.Position = destinationPosition;
					stream.Write( buffer, 0, bytesRead );
					bytesToCopy -= bytesRead;
					destinationPosition += bytesRead;
					sourcePosition += bytesRead;
				} else {
					throw new BlubbZipException( "Unxpected end of stream" );
				}
			}
		}
コード例 #6
0
ファイル: BlubbZipFile.cs プロジェクト: GodLesZ/svn-dump
		void CopyEntryDataDirect( BlubbUpdate update, Stream stream, bool updateCrc, ref long destinationPosition, ref long sourcePosition ) {
			long bytesToCopy = update.Entry.CompressedSize;

			// NOTE: Compressed size is updated elsewhere.
			Crc32 crc = new Crc32();
			byte[] buffer = GetBuffer();

			long targetBytes = bytesToCopy;
			long totalBytesRead = 0;

			int bytesRead;
			do {
				int readSize = buffer.Length;

				if( bytesToCopy < readSize ) {
					readSize = (int)bytesToCopy;
				}

				stream.Position = sourcePosition;
				bytesRead = stream.Read( buffer, 0, readSize );
				if( bytesRead > 0 ) {
					if( updateCrc ) {
						crc.Update( buffer, 0, bytesRead );
					}
					stream.Position = destinationPosition;
					stream.Write( buffer, 0, bytesRead );

					destinationPosition += bytesRead;
					sourcePosition += bytesRead;
					bytesToCopy -= bytesRead;
					totalBytesRead += bytesRead;
				}
			}
			while( ( bytesRead > 0 ) && ( bytesToCopy > 0 ) );

			if( totalBytesRead != targetBytes ) {
				throw new BlubbZipException( string.Format( "Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead ) );
			}

			if( updateCrc ) {
				update.OutEntry.Crc = crc.Value;
			}
		}
コード例 #7
0
ファイル: BlubbZipFile.cs プロジェクト: GodLesZ/svn-dump
		/// <summary>
		/// Get the size of the source descriptor for a <see cref="BlubbUpdate"/>.
		/// </summary>
		/// <param name="update">The update to get the size for.</param>
		/// <returns>The descriptor size, zero if there isnt one.</returns>
		int GetDescriptorSize( BlubbUpdate update ) {
			int result = 0;
			if( ( update.Entry.Flags & (int)GeneralBitFlags.Descriptor ) != 0 ) {
				result = BlubbZipConstants.DataDescriptorSize - 4;
				if( update.Entry.LocalHeaderRequiresBlubb64 ) {
					result = BlubbZipConstants.Blubb64DataDescriptorSize - 4;
				}
			}
			return result;
		}
コード例 #8
0
ファイル: BlubbZipFile.cs プロジェクト: GodLesZ/svn-dump
		void CopyBytes( BlubbUpdate update, Stream destination, Stream source,
			long bytesToCopy, bool updateCrc ) {
			if( destination == source ) {
				throw new InvalidOperationException( "Destination and source are the same" );
			}

			// NOTE: Compressed size is updated elsewhere.
			Crc32 crc = new Crc32();
			byte[] buffer = GetBuffer();

			long targetBytes = bytesToCopy;
			long totalBytesRead = 0;

			int bytesRead;
			do {
				int readSize = buffer.Length;

				if( bytesToCopy < readSize ) {
					readSize = (int)bytesToCopy;
				}

				bytesRead = source.Read( buffer, 0, readSize );
				if( bytesRead > 0 ) {
					if( updateCrc ) {
						crc.Update( buffer, 0, bytesRead );
					}
					destination.Write( buffer, 0, bytesRead );
					bytesToCopy -= bytesRead;
					totalBytesRead += bytesRead;
				}
			}
			while( ( bytesRead > 0 ) && ( bytesToCopy > 0 ) );

			if( totalBytesRead != targetBytes ) {
				throw new BlubbZipException( string.Format( "Failed to copy bytes expected {0} read {1}", targetBytes, totalBytesRead ) );
			}

			if( updateCrc ) {
				update.OutEntry.Crc = crc.Value;
			}
		}
コード例 #9
0
ファイル: BlubbZipFile.cs プロジェクト: GodLesZ/svn-dump
		void CopyDescriptorBytes( BlubbUpdate update, Stream dest, Stream source ) {
			int bytesToCopy = GetDescriptorSize( update );

			if( bytesToCopy > 0 ) {
				byte[] buffer = GetBuffer();

				while( bytesToCopy > 0 ) {
					int readSize = Math.Min( buffer.Length, bytesToCopy );

					int bytesRead = source.Read( buffer, 0, readSize );
					if( bytesRead > 0 ) {
						dest.Write( buffer, 0, bytesRead );
						bytesToCopy -= bytesRead;
					} else {
						throw new BlubbZipException( "Unxpected end of stream" );
					}
				}
			}
		}
コード例 #10
0
ファイル: BlubbZipFile.cs プロジェクト: GodLesZ/svn-dump
		void WriteLocalEntryHeader( BlubbUpdate update ) {
			BlubbZipEntry entry = update.OutEntry;

			// TODO: Local offset will require adjusting for multi-disk blubb files.
			entry.Offset = baseStream_.Position;

			// TODO: Need to clear any entry flags that dont make sense or throw an exception here.
			if( update.Command != UpdateCommand.Copy ) {
				if( entry.CompressionMethod == CompressionMethod.Deflated ) {
					if( entry.Size == 0 ) {
						// No need to compress - no data.
						entry.CompressedSize = entry.Size;
						entry.Crc = 0;
						entry.CompressionMethod = CompressionMethod.Stored;
					}
				} else if( entry.CompressionMethod == CompressionMethod.Stored ) {
					entry.Flags &= ~(int)GeneralBitFlags.Descriptor;
				}

				if( HaveKeys ) {
					entry.IsCrypted = true;
					if( entry.Crc < 0 ) {
						entry.Flags |= (int)GeneralBitFlags.Descriptor;
					}
				} else {
					entry.IsCrypted = false;
				}

				switch( useBlubb64_ ) {
					case UseBlubb64.Dynamic:
						if( entry.Size < 0 ) {
							entry.ForceBlubb64();
						}
						break;

					case UseBlubb64.On:
						entry.ForceBlubb64();
						break;

					case UseBlubb64.Off:
						// Do nothing.  The entry itself may be using Blubb64 independantly.
						break;
				}
			}

			// Write the local file header
			WriteLEInt( BlubbZipConstants.LocalHeaderSignature );

			WriteLEShort( entry.Version );
			WriteLEShort( entry.Flags );

			WriteLEShort( (byte)entry.CompressionMethod );
			WriteLEInt( (int)entry.DosTime );

			if( !entry.HasCrc ) {
				// Note patch address for updating CRC later.
				update.CrcPatchOffset = baseStream_.Position;
				WriteLEInt( (int)0 );
			} else {
				WriteLEInt( unchecked( (int)entry.Crc ) );
			}

			if( entry.LocalHeaderRequiresBlubb64 ) {
				WriteLEInt( -1 );
				WriteLEInt( -1 );
			} else {
				if( ( entry.CompressedSize < 0 ) || ( entry.Size < 0 ) ) {
					update.SizePatchOffset = baseStream_.Position;
				}

				WriteLEInt( (int)entry.CompressedSize );
				WriteLEInt( (int)entry.Size );
			}

			byte[] name = BlubbZipConstants.ConvertToArray( entry.Flags, entry.Name );

			if( name.Length > 0xFFFF ) {
				throw new BlubbZipException( "Entry name too long." );
			}

			BlubbZipExtraData ed = new BlubbZipExtraData( entry.ExtraData );

			if( entry.LocalHeaderRequiresBlubb64 ) {
				ed.StartNewEntry();

				// Local entry header always includes size and compressed size.
				// NOTE the order of these fields is reversed when compared to the normal headers!
				ed.AddLeLong( entry.Size );
				ed.AddLeLong( entry.CompressedSize );
				ed.AddNewEntry( 1 );
			} else {
				ed.Delete( 1 );
			}

			entry.ExtraData = ed.GetEntryData();

			WriteLEShort( name.Length );
			WriteLEShort( entry.ExtraData.Length );

			if( name.Length > 0 ) {
				baseStream_.Write( name, 0, name.Length );
			}

			if( entry.LocalHeaderRequiresBlubb64 ) {
				if( !ed.Find( 1 ) ) {
					throw new BlubbZipException( "Internal error cannot find extra data" );
				}

				update.SizePatchOffset = baseStream_.Position + ed.CurrentReadIndex;
			}

			if( entry.ExtraData.Length > 0 ) {
				baseStream_.Write( entry.ExtraData, 0, entry.ExtraData.Length );
			}
		}
コード例 #11
0
ファイル: BlubbZipFile.cs プロジェクト: GodLesZ/svn-dump
		// Adding Entries

		void AddUpdate( BlubbUpdate update ) {
			contentsEdited_ = true;

			int index = FindExistingUpdate( update.Entry.Name );

			if( index >= 0 ) {
				if( updates_[ index ] == null ) {
					updateCount_ += 1;
				}

				// Direct replacement is faster than delete and add.
				updates_[ index ] = update;
			} else {
				index = updates_.Add( update );
				updateCount_ += 1;
				updateIndex_.Add( update.Entry.Name, index );
			}
		}